From 8e3314e68059e57c3ec4916c478f0d002fa95ffe Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 26 Oct 2023 18:17:45 +0200 Subject: [PATCH 1/2] WIP --- crates/gpui2/src/app.rs | 7 +- crates/gpui2/src/app/async_context.rs | 14 +-- crates/gpui2/src/app/entity_map.rs | 4 +- crates/gpui2/src/app/model_context.rs | 6 +- crates/gpui2/src/app/test_context.rs | 6 +- crates/gpui2/src/gpui2.rs | 20 ++-- crates/gpui2/src/interactive.rs | 3 +- crates/gpui2/src/view.rs | 89 +++++++++++----- crates/gpui2/src/window.rs | 142 +++++++++++++------------- 9 files changed, 164 insertions(+), 127 deletions(-) diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 9e96e5a437196795feca42c0d65dfe28b55e46f6..35c2272c3b03844755c10130d15fc305d6080efe 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -130,6 +130,7 @@ pub struct AppContext { pub(crate) text_style_stack: Vec, pub(crate) globals_by_type: HashMap, pub(crate) unit_entity: Handle<()>, + pub(crate) unit_view: View<()>, pub(crate) entities: EntityMap, pub(crate) windows: SlotMap>, pub(crate) keymap: Arc>, @@ -653,12 +654,12 @@ impl AppContext { } impl Context for AppContext { - type EntityContext<'a, 'w, T> = ModelContext<'a, T>; + type EntityContext<'a, T> = ModelContext<'a, T>; type Result = T; fn entity( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, + build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, ) -> Handle { self.update(|cx| { let slot = cx.entities.reserve(); @@ -670,7 +671,7 @@ impl Context for AppContext { fn update_entity( &mut self, handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, + update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, ) -> R { self.update(|cx| { let mut entity = cx.entities.lease(handle); diff --git a/crates/gpui2/src/app/async_context.rs b/crates/gpui2/src/app/async_context.rs index 32b44dd413080b22c91e0c86bd8fb71b7343042c..d49f2ab934e52cba7b66cfb7586903792c6d9341 100644 --- a/crates/gpui2/src/app/async_context.rs +++ b/crates/gpui2/src/app/async_context.rs @@ -1,6 +1,6 @@ use crate::{ AnyWindowHandle, AppContext, Context, Executor, Handle, MainThread, ModelContext, Result, Task, - ViewContext, WindowContext, + WindowContext, }; use anyhow::anyhow; use derive_more::{Deref, DerefMut}; @@ -14,12 +14,12 @@ pub struct AsyncAppContext { } impl Context for AsyncAppContext { - type EntityContext<'a, 'w, T> = ModelContext<'a, T>; + type EntityContext<'a, T> = ModelContext<'a, T>; type Result = Result; fn entity( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, + build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, ) -> Self::Result> where T: 'static + Send, @@ -35,7 +35,7 @@ impl Context for AsyncAppContext { fn update_entity( &mut self, handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, + update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, ) -> Self::Result { let app = self .app @@ -216,12 +216,12 @@ impl AsyncWindowContext { } impl Context for AsyncWindowContext { - type EntityContext<'a, 'w, T> = ViewContext<'a, 'w, T>; + type EntityContext<'a, T> = ModelContext<'a, T>; type Result = Result; fn entity( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, + build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, ) -> Result> where T: 'static + Send, @@ -233,7 +233,7 @@ impl Context for AsyncWindowContext { fn update_entity( &mut self, handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, + update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, ) -> Result { self.app .update_window(self.window, |cx| cx.update_entity(handle, update)) diff --git a/crates/gpui2/src/app/entity_map.rs b/crates/gpui2/src/app/entity_map.rs index be50fabc10a252df28caf5f7aad0ccb1c6a42ba7..f3ae67836d22edd3c5da0de5d83999b8b4a981b8 100644 --- a/crates/gpui2/src/app/entity_map.rs +++ b/crates/gpui2/src/app/entity_map.rs @@ -284,7 +284,7 @@ impl Handle { pub fn update( &self, cx: &mut C, - update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R, + update: impl FnOnce(&mut T, &mut C::EntityContext<'_, T>) -> R, ) -> C::Result where C: Context, @@ -427,7 +427,7 @@ impl WeakHandle { pub fn update( &self, cx: &mut C, - update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R, + update: impl FnOnce(&mut T, &mut C::EntityContext<'_, T>) -> R, ) -> Result where C: Context, diff --git a/crates/gpui2/src/app/model_context.rs b/crates/gpui2/src/app/model_context.rs index 97a9c307215cef5f1184ce861970cba407d98f13..effda37b737b5e5529fb32479b6e9e9b20b19ea6 100644 --- a/crates/gpui2/src/app/model_context.rs +++ b/crates/gpui2/src/app/model_context.rs @@ -224,12 +224,12 @@ where } impl<'a, T> Context for ModelContext<'a, T> { - type EntityContext<'b, 'c, U> = ModelContext<'b, U>; + type EntityContext<'b, U> = ModelContext<'b, U>; type Result = U; fn entity( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U, + build_entity: impl FnOnce(&mut Self::EntityContext<'_, U>) -> U, ) -> Handle where U: 'static + Send, @@ -240,7 +240,7 @@ impl<'a, T> Context for ModelContext<'a, T> { fn update_entity( &mut self, handle: &Handle, - update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R, + update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, U>) -> R, ) -> R { self.app.update_entity(handle, update) } diff --git a/crates/gpui2/src/app/test_context.rs b/crates/gpui2/src/app/test_context.rs index 5793ebc9adf80d1729e1315cc27d9165c5dad14d..435349ca2a25aa447bff2778ee4d91795794acbd 100644 --- a/crates/gpui2/src/app/test_context.rs +++ b/crates/gpui2/src/app/test_context.rs @@ -12,12 +12,12 @@ pub struct TestAppContext { } impl Context for TestAppContext { - type EntityContext<'a, 'w, T> = ModelContext<'a, T>; + type EntityContext<'a, T> = ModelContext<'a, T>; type Result = T; fn entity( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, + build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, ) -> Self::Result> where T: 'static + Send, @@ -29,7 +29,7 @@ impl Context for TestAppContext { fn update_entity( &mut self, handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, + update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, ) -> Self::Result { let mut lock = self.app.lock(); lock.update_entity(handle, update) diff --git a/crates/gpui2/src/gpui2.rs b/crates/gpui2/src/gpui2.rs index 163ef9380927da76ec43a4ca676c41ae646046ba..49b1611c3e8e7521a1ae4ca290f837efc689f336 100644 --- a/crates/gpui2/src/gpui2.rs +++ b/crates/gpui2/src/gpui2.rs @@ -70,12 +70,12 @@ use taffy::TaffyLayoutEngine; type AnyBox = Box; pub trait Context { - type EntityContext<'a, 'w, T>; + type EntityContext<'a, T>; type Result; fn entity( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, + build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, ) -> Self::Result> where T: 'static + Send; @@ -83,7 +83,7 @@ pub trait Context { fn update_entity( &mut self, handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, + update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, ) -> Self::Result; } @@ -111,12 +111,12 @@ impl DerefMut for MainThread { } impl Context for MainThread { - type EntityContext<'a, 'w, T> = MainThread>; + type EntityContext<'a, T> = MainThread>; type Result = C::Result; fn entity( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, + build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, ) -> Self::Result> where T: 'static + Send, @@ -124,8 +124,8 @@ impl Context for MainThread { self.0.entity(|cx| { let cx = unsafe { mem::transmute::< - &mut C::EntityContext<'_, '_, T>, - &mut MainThread>, + &mut C::EntityContext<'_, T>, + &mut MainThread>, >(cx) }; build_entity(cx) @@ -135,13 +135,13 @@ impl Context for MainThread { fn update_entity( &mut self, handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, + update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, ) -> Self::Result { self.0.update_entity(handle, |entity, cx| { let cx = unsafe { mem::transmute::< - &mut C::EntityContext<'_, '_, T>, - &mut MainThread>, + &mut C::EntityContext<'_, T>, + &mut MainThread>, >(cx) }; update(entity, cx) diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index ad3eddfa62defc4b69df080cf09ebcd4b9057a4d..b10c697cac9b0d7f85f87f79acd4158266bfaa46 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -331,9 +331,8 @@ pub trait StatefulInteractive: StatelessInteractive { self.stateful_interaction().drag_listener = Some(Box::new(move |view_state, cursor_offset, cx| { let drag = listener(view_state, cx); - let view_handle = cx.handle().upgrade().unwrap(); let drag_handle_view = Some( - view(view_handle, move |view_state, cx| { + view(cx.handle().upgrade().unwrap(), move |view_state, cx| { (drag.render_drag_handle)(view_state, cx) }) .into_any(), diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index d2fe143faa300a87830020011d05c7584ba32b47..50a6dcab08ba401bd17c3725cebaa0a1c3745fa0 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -1,31 +1,18 @@ -use parking_lot::Mutex; - use crate::{ AnyBox, AnyElement, BorrowWindow, Bounds, Component, Element, ElementId, EntityId, Handle, - LayoutId, Pixels, ViewContext, WindowContext, + LayoutId, Pixels, ViewContext, WeakHandle, WindowContext, +}; +use parking_lot::Mutex; +use std::{ + marker::PhantomData, + sync::{Arc, Weak}, }; -use std::{marker::PhantomData, sync::Arc}; pub struct View { - state: Handle, + pub(crate) state: Handle, render: Arc) -> AnyElement + Send + 'static>>, } -impl View { - pub fn into_any(self) -> AnyView { - AnyView(Arc::new(self)) - } -} - -impl Clone for View { - fn clone(&self) -> Self { - Self { - state: self.state.clone(), - render: self.render.clone(), - } - } -} - pub fn view( state: Handle, render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, @@ -41,6 +28,43 @@ where } } +impl View { + pub fn into_any(self) -> AnyView { + AnyView(Arc::new(self)) + } + + pub fn downgrade(&self) -> WeakView { + WeakView { + state: self.state.downgrade(), + render: Arc::downgrade(&self.render), + } + } +} + +impl View { + pub fn update( + &self, + cx: &mut WindowContext, + f: impl FnOnce(&mut V, &mut ViewContext) -> R, + ) -> R { + let this = self.clone(); + let mut lease = cx.app.entities.lease(&self.state); + let mut cx = ViewContext::mutable(&mut *cx.app, &mut *cx.window, this); + let result = f(&mut *lease, &mut cx); + cx.app.entities.end_lease(lease); + result + } +} + +impl Clone for View { + fn clone(&self) -> Self { + Self { + state: self.state.clone(), + render: self.render.clone(), + } + } +} + impl Component for View { fn render(self) -> AnyElement { AnyElement::new(EraseViewState { @@ -63,7 +87,7 @@ impl Element<()> for View { _: Option, cx: &mut ViewContext<()>, ) -> Self::ElementState { - self.state.update(cx, |state, cx| { + self.update(cx, |state, cx| { let mut any_element = (self.render.lock())(state, cx); any_element.initialize(state, cx); any_element @@ -76,7 +100,7 @@ impl Element<()> for View { element: &mut Self::ElementState, cx: &mut ViewContext<()>, ) -> LayoutId { - self.state.update(cx, |state, cx| element.layout(state, cx)) + self.update(cx, |state, cx| element.layout(state, cx)) } fn paint( @@ -86,7 +110,20 @@ impl Element<()> for View { element: &mut Self::ElementState, cx: &mut ViewContext<()>, ) { - self.state.update(cx, |state, cx| element.paint(state, cx)) + self.update(cx, |state, cx| element.paint(state, cx)) + } +} + +pub struct WeakView { + state: WeakHandle, + render: Weak) -> AnyElement + Send + 'static>>, +} + +impl WeakView { + pub fn upgrade(&self) -> Option> { + let state = self.state.upgrade()?; + let render = self.render.upgrade()?; + Some(View { state, render }) } } @@ -153,7 +190,7 @@ impl ViewObject for View { fn initialize(&self, cx: &mut WindowContext) -> AnyBox { cx.with_element_id(self.entity_id(), |_global_id, cx| { - self.state.update(cx, |state, cx| { + self.update(cx, |state, cx| { let mut any_element = Box::new((self.render.lock())(state, cx)); any_element.initialize(state, cx); any_element as AnyBox @@ -163,7 +200,7 @@ impl ViewObject for View { fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId { cx.with_element_id(self.entity_id(), |_global_id, cx| { - self.state.update(cx, |state, cx| { + self.update(cx, |state, cx| { let element = element.downcast_mut::>().unwrap(); element.layout(state, cx) }) @@ -172,7 +209,7 @@ impl ViewObject for View { fn paint(&self, _: Bounds, element: &mut AnyBox, cx: &mut WindowContext) { cx.with_element_id(self.entity_id(), |_global_id, cx| { - self.state.update(cx, |state, cx| { + self.update(cx, |state, cx| { let element = element.downcast_mut::>().unwrap(); element.paint(state, cx); }); diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 4a203014dbe15168170e7e948950f8e77fffe7c1..bb5cfcbf9176a68b887e0789bdc7c4333076ad15 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -3,12 +3,12 @@ use crate::{ Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect, Element, EntityId, EventEmitter, ExternalPaths, FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, - KeyMatcher, Keystroke, LayoutId, MainThread, MainThreadOnly, 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, WeakHandle, WindowOptions, - SUBPIXEL_VARIANTS, + 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, WeakHandle, + WeakView, WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::Result; use collections::HashMap; @@ -281,7 +281,7 @@ impl ContentMask { } pub struct WindowContext<'a, 'w> { - app: Reference<'a, AppContext>, + pub(crate) app: Reference<'a, AppContext>, pub(crate) window: Reference<'w, Window>, } @@ -800,42 +800,45 @@ impl<'a, 'w> WindowContext<'a, 'w> { pub(crate) fn draw(&mut self) { let unit_entity = self.unit_entity.clone(); - self.update_entity(&unit_entity, |view, cx| { - cx.start_frame(); + let mut root_view = self.window.root_view.take().unwrap(); + let mut root_view_cx = ViewContext::mutable( + &mut self.app, + &mut self.window, + self.unit_entity.downgrade(), + ); - let mut root_view = cx.window.root_view.take().unwrap(); + root_view_cx.start_frame(); - cx.stack(0, |cx| { - let available_space = cx.window.content_size.map(Into::into); - draw_any_view(&mut root_view, available_space, cx); - }); + root_view_cx.stack(0, |cx| { + let available_space = cx.window.content_size.map(Into::into); + draw_any_view(&mut root_view, available_space, cx); + }); - if let Some(mut active_drag) = cx.active_drag.take() { - cx.stack(1, |cx| { - let offset = cx.mouse_position() - active_drag.cursor_offset; - cx.with_element_offset(Some(offset), |cx| { - let available_space = - size(AvailableSpace::MinContent, AvailableSpace::MinContent); - if let Some(drag_handle_view) = &mut active_drag.drag_handle_view { - draw_any_view(drag_handle_view, available_space, cx); - } - cx.active_drag = Some(active_drag); - }); + if let Some(mut active_drag) = self.app.active_drag.take() { + root_view_cx.stack(1, |cx| { + let offset = cx.mouse_position() - active_drag.cursor_offset; + cx.with_element_offset(Some(offset), |cx| { + let available_space = + size(AvailableSpace::MinContent, AvailableSpace::MinContent); + if let Some(drag_handle_view) = &mut active_drag.drag_handle_view { + draw_any_view(drag_handle_view, available_space, cx); + } + cx.active_drag = Some(active_drag); }); - } + }); + } - cx.window.root_view = Some(root_view); - let scene = cx.window.scene_builder.build(); + self.window.root_view = Some(root_view); + let scene = self.window.scene_builder.build(); - cx.run_on_main(view, |_, cx| { - cx.window - .platform_window - .borrow_on_main_thread() - .draw(scene); - cx.window.dirty = false; - }) - .detach(); - }); + self.run_on_main(|cx| { + cx.window + .platform_window + .borrow_on_main_thread() + .draw(scene); + cx.window.dirty = false; + }) + .detach(); fn draw_any_view( view: &mut AnyView, @@ -1169,34 +1172,30 @@ impl<'a, 'w> WindowContext<'a, 'w> { } impl Context for WindowContext<'_, '_> { - type EntityContext<'a, 'w, T> = ViewContext<'a, 'w, T>; + type EntityContext<'a, T> = ModelContext<'a, T>; type Result = T; fn entity( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, + build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, ) -> Handle where T: 'static + Send, { let slot = self.app.entities.reserve(); - let entity = build_entity(&mut ViewContext::mutable( - &mut *self.app, - &mut self.window, - slot.downgrade(), - )); + let entity = build_entity(&mut ModelContext::mutable(&mut *self.app, slot.downgrade())); self.entities.insert(slot, entity) } fn update_entity( &mut self, handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, + update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, ) -> R { let mut entity = self.entities.lease(handle); let result = update( &mut *entity, - &mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.downgrade()), + &mut ModelContext::mutable(&mut *self.app, handle.downgrade()), ); self.entities.end_lease(entity); result @@ -1389,7 +1388,7 @@ impl BorrowWindow for T where T: BorrowMut + BorrowMut {} pub struct ViewContext<'a, 'w, V> { window_cx: WindowContext<'a, 'w>, - view_state: WeakHandle, + view: View, } impl Borrow for ViewContext<'_, '_, V> { @@ -1417,15 +1416,19 @@ impl BorrowMut for ViewContext<'_, '_, V> { } impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { - fn mutable(app: &'a mut AppContext, window: &'w mut Window, view_state: WeakHandle) -> Self { + pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window, view: View) -> Self { Self { window_cx: WindowContext::mutable(app, window), - view_state, + view, } } + pub fn view(&self) -> WeakView { + self.view.downgrade() + } + pub fn handle(&self) -> WeakHandle { - self.view_state.clone() + self.view.state.downgrade() } pub fn stack(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R { @@ -1439,10 +1442,8 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { where V: Any + Send, { - let entity = self.handle(); - self.window_cx.on_next_frame(move |cx| { - entity.update(cx, f).ok(); - }); + let view = self.view(); + self.window_cx.on_next_frame(move |cx| view.update(cx, f)); } pub fn observe( @@ -1454,7 +1455,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { E: 'static, V: Any + Send, { - let this = self.handle(); + let view = self.view(); let handle = handle.downgrade(); let window_handle = self.window.handle; self.app.observers.insert( @@ -1462,7 +1463,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { Box::new(move |cx| { cx.update_window(window_handle.id, |cx| { if let Some(handle) = handle.upgrade() { - this.update(cx, |this, cx| on_notify(this, handle, cx)) + view.update(cx, |this, cx| on_notify(this, handle, cx)) .is_ok() } else { false @@ -1480,7 +1481,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { + Send + 'static, ) -> Subscription { - let this = self.handle(); + let this = self.view(); let handle = handle.downgrade(); let window_handle = self.window.handle; self.app.event_listeners.insert( @@ -1490,7 +1491,6 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { if let Some(handle) = handle.upgrade() { let event = event.downcast_ref().expect("invalid event type"); this.update(cx, |this, cx| on_event(this, handle, event, cx)) - .is_ok() } else { false } @@ -1506,7 +1506,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.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?") @@ -1523,7 +1523,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { where V: Any + Send, { - let this = self.handle(); + let this = self.view(); let window_handle = self.window.handle; self.app.release_listeners.insert( handle.entity_id, @@ -1540,7 +1540,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.entity_id, }); } @@ -1548,7 +1548,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { &mut self, listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + Send + 'static, ) { - let handle = self.handle(); + let handle = self.view(); self.window.focus_listeners.push(Box::new(move |event, cx| { handle .update(cx, |view, cx| listener(view, event, cx)) @@ -1564,7 +1564,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { let old_stack_len = self.window.key_dispatch_stack.len(); if !self.window.freeze_key_dispatch_stack { for (event_type, listener) in key_listeners { - let handle = self.handle(); + let handle = self.view(); let listener = Box::new( move |event: &dyn Any, context_stack: &[&DispatchContext], @@ -1654,7 +1654,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { let cx = unsafe { mem::transmute::<&mut Self, &mut MainThread>(self) }; Task::ready(Ok(f(view, cx))) } else { - let handle = self.handle().upgrade().unwrap(); + let handle = self.view().upgrade().unwrap(); self.window_cx.run_on_main(move |cx| handle.update(cx, f)) } } @@ -1667,7 +1667,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { R: Send + 'static, Fut: Future + Send + 'static, { - let handle = self.handle(); + let handle = self.view(); self.window_cx.spawn(move |_, cx| { let result = f(handle, cx); async move { result.await } @@ -1689,7 +1689,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { f: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) + Send + 'static, ) -> Subscription { let window_id = self.window.handle.id; - let handle = self.handle(); + let handle = self.view(); self.global_observers.insert( TypeId::of::(), Box::new(move |cx| { @@ -1705,7 +1705,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { &mut self, handler: impl Fn(&mut V, &Event, DispatchPhase, &mut ViewContext) + Send + 'static, ) { - let handle = self.handle().upgrade().unwrap(); + let handle = self.view().upgrade().unwrap(); self.window_cx.on_mouse_event(move |event, phase, cx| { handle.update(cx, |view, cx| { handler(view, event, phase, cx); @@ -1720,7 +1720,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.entity_id; self.app.push_effect(Effect::Emit { emitter, event: Box::new(event), @@ -1729,12 +1729,12 @@ where } impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> { - type EntityContext<'b, 'c, U> = ViewContext<'b, 'c, U>; + type EntityContext<'b, U> = ModelContext<'b, U>; type Result = U; fn entity( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, + build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, ) -> Handle where T: 'static + Send, @@ -1745,7 +1745,7 @@ impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> { fn update_entity( &mut self, handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, + update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, ) -> R { self.window_cx.update_entity(handle, update) } From a1c382685871fe25fd244f5182108faff16edcc8 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 26 Oct 2023 19:41:42 +0200 Subject: [PATCH 2/2] Add View::update which provides a ViewContext --- crates/gpui2/src/app.rs | 7 +- crates/gpui2/src/gpui2.rs | 62 +++++++ crates/gpui2/src/interactive.rs | 7 +- crates/gpui2/src/view.rs | 84 +++++++--- crates/gpui2/src/window.rs | 150 ++++++++++------- crates/storybook2/src/stories/focus.rs | 151 +++++++++--------- crates/storybook2/src/stories/kitchen_sink.rs | 10 +- crates/storybook2/src/stories/scroll.rs | 6 +- crates/storybook2/src/stories/text.rs | 4 +- crates/storybook2/src/story_selector.rs | 82 +++++----- crates/storybook2/src/storybook2.rs | 6 +- crates/ui2/src/components/buffer_search.rs | 10 +- crates/ui2/src/components/editor_pane.rs | 15 +- crates/ui2/src/components/title_bar.rs | 28 ++-- crates/ui2/src/components/workspace.rs | 20 ++- crates/ui2/src/static_data.rs | 4 +- crates/ui2/src/theme.rs | 6 +- 17 files changed, 404 insertions(+), 248 deletions(-) diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 35c2272c3b03844755c10130d15fc305d6080efe..35df72769ba4e6f3a5d1abcaec09b1cf13f3b29d 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -129,8 +129,6 @@ pub struct AppContext { pub(crate) image_cache: ImageCache, pub(crate) text_style_stack: Vec, pub(crate) globals_by_type: HashMap, - pub(crate) unit_entity: Handle<()>, - pub(crate) unit_view: View<()>, pub(crate) entities: EntityMap, pub(crate) windows: SlotMap>, pub(crate) keymap: Arc>, @@ -162,8 +160,8 @@ impl AppContext { ); let text_system = Arc::new(TextSystem::new(platform.text_system())); - let mut entities = EntityMap::new(); - let unit_entity = entities.insert(entities.reserve(), ()); + let entities = EntityMap::new(); + let app_metadata = AppMetadata { os_name: platform.os_name(), os_version: platform.os_version().ok(), @@ -185,7 +183,6 @@ impl AppContext { image_cache: ImageCache::new(http_client), text_style_stack: Vec::new(), globals_by_type: HashMap::default(), - unit_entity, entities, windows: SlotMap::with_key(), keymap: Arc::new(Mutex::new(Keymap::default())), diff --git a/crates/gpui2/src/gpui2.rs b/crates/gpui2/src/gpui2.rs index 49b1611c3e8e7521a1ae4ca290f837efc689f336..f6fa280c760b9a883aba3d816370f9ac7217e613 100644 --- a/crates/gpui2/src/gpui2.rs +++ b/crates/gpui2/src/gpui2.rs @@ -87,6 +87,25 @@ pub trait Context { ) -> Self::Result; } +pub trait VisualContext: Context { + type ViewContext<'a, 'w, V>; + + fn build_view( + &mut self, + build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, + render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, + ) -> Self::Result> + where + E: Component, + V: 'static + Send; + + fn update_view( + &mut self, + view: &View, + update: impl FnOnce(&mut V, &mut Self::ViewContext<'_, '_, V>) -> R, + ) -> Self::Result; +} + pub enum GlobalKey { Numeric(usize), View(EntityId), @@ -149,6 +168,49 @@ impl Context for MainThread { } } +impl VisualContext for MainThread { + type ViewContext<'a, 'w, V> = MainThread>; + + fn build_view( + &mut self, + build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, + render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, + ) -> Self::Result> + where + E: Component, + V: 'static + Send, + { + self.0.build_view( + |cx| { + let cx = unsafe { + mem::transmute::< + &mut C::ViewContext<'_, '_, V>, + &mut MainThread>, + >(cx) + }; + build_entity(cx) + }, + render, + ) + } + + fn update_view( + &mut self, + view: &View, + update: impl FnOnce(&mut V, &mut Self::ViewContext<'_, '_, V>) -> R, + ) -> Self::Result { + self.0.update_view(view, |view_state, cx| { + let cx = unsafe { + mem::transmute::< + &mut C::ViewContext<'_, '_, V>, + &mut MainThread>, + >(cx) + }; + update(view_state, cx) + }) + } +} + pub trait BorrowAppContext { fn with_text_style(&mut self, style: TextStyleRefinement, f: F) -> R where diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index b10c697cac9b0d7f85f87f79acd4158266bfaa46..a617792bfb88685351c8d9e4eb17652cc49b6dcd 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -1,7 +1,8 @@ use crate::{ - point, px, view, Action, AnyBox, AnyDrag, AppContext, BorrowWindow, Bounds, Component, + point, px, Action, AnyBox, AnyDrag, AppContext, BorrowWindow, Bounds, Component, DispatchContext, DispatchPhase, Element, ElementId, FocusHandle, KeyMatch, Keystroke, - Modifiers, Overflow, Pixels, Point, SharedString, Size, Style, StyleRefinement, ViewContext, + Modifiers, Overflow, Pixels, Point, SharedString, Size, Style, StyleRefinement, View, + ViewContext, }; use collections::HashMap; use derive_more::{Deref, DerefMut}; @@ -332,7 +333,7 @@ pub trait StatefulInteractive: StatelessInteractive { Some(Box::new(move |view_state, cursor_offset, cx| { let drag = listener(view_state, cx); let drag_handle_view = Some( - view(cx.handle().upgrade().unwrap(), move |view_state, cx| { + View::for_handle(cx.handle().upgrade().unwrap(), move |view_state, cx| { (drag.render_drag_handle)(view_state, cx) }) .into_any(), diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index 50a6dcab08ba401bd17c3725cebaa0a1c3745fa0..4bb9c3d3a825bf54c8192999baf63db7cbf2300c 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -1,7 +1,9 @@ use crate::{ - AnyBox, AnyElement, BorrowWindow, Bounds, Component, Element, ElementId, EntityId, Handle, - LayoutId, Pixels, ViewContext, WeakHandle, WindowContext, + AnyBox, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId, + EntityId, Handle, LayoutId, Pixels, Size, ViewContext, VisualContext, WeakHandle, + WindowContext, }; +use anyhow::{Context, Result}; use parking_lot::Mutex; use std::{ marker::PhantomData, @@ -13,18 +15,20 @@ pub struct View { render: Arc) -> AnyElement + Send + 'static>>, } -pub fn view( - state: Handle, - render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, -) -> View -where - E: Component, -{ - View { - state, - render: Arc::new(Mutex::new( - move |state: &mut V, cx: &mut ViewContext<'_, '_, V>| render(state, cx).render(), - )), +impl View { + pub fn for_handle( + state: Handle, + render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, + ) -> View + where + E: Component, + { + View { + state, + render: Arc::new(Mutex::new( + move |state: &mut V, cx: &mut ViewContext<'_, '_, V>| render(state, cx).render(), + )), + } } } @@ -42,17 +46,15 @@ impl View { } impl View { - pub fn update( + pub fn update( &self, - cx: &mut WindowContext, - f: impl FnOnce(&mut V, &mut ViewContext) -> R, - ) -> R { - let this = self.clone(); - let mut lease = cx.app.entities.lease(&self.state); - let mut cx = ViewContext::mutable(&mut *cx.app, &mut *cx.window, this); - let result = f(&mut *lease, &mut cx); - cx.app.entities.end_lease(lease); - result + cx: &mut C, + f: impl FnOnce(&mut V, &mut C::ViewContext<'_, '_, V>) -> R, + ) -> C::Result + where + C: VisualContext, + { + cx.update_view(self, f) } } @@ -115,16 +117,34 @@ impl Element<()> for View { } pub struct WeakView { - state: WeakHandle, + pub(crate) state: WeakHandle, render: Weak) -> AnyElement + Send + 'static>>, } -impl WeakView { +impl WeakView { pub fn upgrade(&self) -> Option> { let state = self.state.upgrade()?; let render = self.render.upgrade()?; Some(View { state, render }) } + + pub fn update( + &self, + cx: &mut WindowContext, + f: impl FnOnce(&mut V, &mut ViewContext) -> R, + ) -> Result { + let view = self.upgrade().context("error upgrading view")?; + Ok(view.update(cx, f)) + } +} + +impl Clone for WeakView { + fn clone(&self) -> Self { + Self { + state: self.state.clone(), + render: self.render.clone(), + } + } } struct EraseViewState { @@ -220,6 +240,18 @@ impl ViewObject for View { #[derive(Clone)] pub struct AnyView(Arc); +impl AnyView { + 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); + 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); + } +} + impl Component for AnyView { fn render(self) -> AnyElement { AnyElement::new(EraseAnyViewState { diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index bb5cfcbf9176a68b887e0789bdc7c4333076ad15..cf15082d31e7c48f8559ef2713ff7b371fae4e63 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, - Element, 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, WeakHandle, - WeakView, WindowOptions, SUBPIXEL_VARIANTS, + 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; @@ -150,7 +150,7 @@ pub struct Window { sprite_atlas: Arc, rem_size: Pixels, content_size: Size, - layout_engine: TaffyLayoutEngine, + pub(crate) layout_engine: TaffyLayoutEngine, pub(crate) root_view: Option, pub(crate) element_id_stack: GlobalElementId, prev_frame_element_states: HashMap, @@ -799,29 +799,23 @@ impl<'a, 'w> WindowContext<'a, 'w> { } pub(crate) fn draw(&mut self) { - let unit_entity = self.unit_entity.clone(); - let mut root_view = self.window.root_view.take().unwrap(); - let mut root_view_cx = ViewContext::mutable( - &mut self.app, - &mut self.window, - self.unit_entity.downgrade(), - ); + let root_view = self.window.root_view.take().unwrap(); - root_view_cx.start_frame(); + self.start_frame(); - root_view_cx.stack(0, |cx| { + self.stack(0, |cx| { let available_space = cx.window.content_size.map(Into::into); - draw_any_view(&mut root_view, available_space, cx); + root_view.draw(available_space, cx); }); if let Some(mut active_drag) = self.app.active_drag.take() { - root_view_cx.stack(1, |cx| { + self.stack(1, |cx| { let offset = cx.mouse_position() - active_drag.cursor_offset; cx.with_element_offset(Some(offset), |cx| { let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent); if let Some(drag_handle_view) = &mut active_drag.drag_handle_view { - draw_any_view(drag_handle_view, available_space, cx); + drag_handle_view.draw(available_space, cx); } cx.active_drag = Some(active_drag); }); @@ -839,23 +833,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { cx.window.dirty = false; }) .detach(); - - fn draw_any_view( - view: &mut AnyView, - available_space: Size, - cx: &mut ViewContext<()>, - ) { - cx.with_optional_element_state(view.id(), |element_state, cx| { - let mut element_state = view.initialize(&mut (), element_state, cx); - let layout_id = view.layout(&mut (), &mut element_state, cx); - cx.window - .layout_engine - .compute_layout(layout_id, available_space); - let bounds = cx.window.layout_engine.layout_bounds(layout_id); - view.paint(bounds, &mut (), &mut element_state, cx); - ((), element_state) - }); - } } fn start_frame(&mut self) { @@ -1202,6 +1179,39 @@ impl Context for WindowContext<'_, '_> { } } +impl VisualContext for WindowContext<'_, '_> { + type ViewContext<'a, 'w, V> = ViewContext<'a, 'w, V>; + + fn build_view( + &mut self, + build_view_state: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, + render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, + ) -> Self::Result> + where + E: crate::Component, + V: 'static + Send, + { + let slot = self.app.entities.reserve(); + let view = View::for_handle(slot.clone(), render); + let mut cx = ViewContext::mutable(&mut *self.app, &mut *self.window, view.downgrade()); + let entity = build_view_state(&mut cx); + self.entities.insert(slot, entity); + view + } + + fn update_view( + &mut self, + view: &View, + update: impl FnOnce(&mut T, &mut Self::ViewContext<'_, '_, T>) -> R, + ) -> Self::Result { + let mut lease = self.app.entities.lease(&view.state); + 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); + result + } +} + impl<'a, 'w> std::ops::Deref for WindowContext<'a, 'w> { type Target = AppContext; @@ -1388,7 +1398,7 @@ impl BorrowWindow for T where T: BorrowMut + BorrowMut {} pub struct ViewContext<'a, 'w, V> { window_cx: WindowContext<'a, 'w>, - view: View, + view: WeakView, } impl Borrow for ViewContext<'_, '_, V> { @@ -1416,7 +1426,11 @@ impl BorrowMut for ViewContext<'_, '_, V> { } impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { - pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window, view: View) -> Self { + pub(crate) fn mutable( + app: &'a mut AppContext, + window: &'w mut Window, + view: WeakView, + ) -> Self { Self { window_cx: WindowContext::mutable(app, window), view, @@ -1424,11 +1438,11 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { } pub fn view(&self) -> WeakView { - self.view.downgrade() + self.view.clone() } pub fn handle(&self) -> WeakHandle { - self.view.state.downgrade() + self.view.state.clone() } pub fn stack(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R { @@ -1442,7 +1456,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { where V: Any + Send, { - let view = self.view(); + let view = self.view().upgrade().unwrap(); self.window_cx.on_next_frame(move |cx| view.update(cx, f)); } @@ -1481,7 +1495,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { + Send + 'static, ) -> Subscription { - let this = self.view(); + let view = self.view(); let handle = handle.downgrade(); let window_handle = self.window.handle; self.app.event_listeners.insert( @@ -1490,7 +1504,8 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { cx.update_window(window_handle.id, |cx| { if let Some(handle) = handle.upgrade() { let event = event.downcast_ref().expect("invalid event type"); - this.update(cx, |this, cx| on_event(this, handle, event, cx)) + view.update(cx, |this, cx| on_event(this, handle, event, cx)) + .is_ok() } else { false } @@ -1506,7 +1521,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { ) -> Subscription { let window_handle = self.window.handle; self.app.release_listeners.insert( - self.view.entity_id, + self.view.state.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?") @@ -1523,15 +1538,14 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { where V: Any + Send, { - let this = self.view(); + let view = self.view(); let window_handle = self.window.handle; self.app.release_listeners.insert( handle.entity_id, Box::new(move |entity, cx| { let entity = entity.downcast_mut().expect("invalid entity type"); - // todo!("are we okay with silently swallowing the error?") let _ = cx.update_window(window_handle.id, |cx| { - this.update(cx, |this, cx| on_release(this, entity, cx)) + view.update(cx, |this, cx| on_release(this, entity, cx)) }); }), ) @@ -1540,7 +1554,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.entity_id, + emitter: self.view.state.entity_id, }); } @@ -1654,22 +1668,22 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { let cx = unsafe { mem::transmute::<&mut Self, &mut MainThread>(self) }; Task::ready(Ok(f(view, cx))) } else { - let handle = self.view().upgrade().unwrap(); - self.window_cx.run_on_main(move |cx| handle.update(cx, f)) + let view = self.view().upgrade().unwrap(); + self.window_cx.run_on_main(move |cx| view.update(cx, f)) } } pub fn spawn( &mut self, - f: impl FnOnce(WeakHandle, AsyncWindowContext) -> Fut + Send + 'static, + f: impl FnOnce(WeakView, AsyncWindowContext) -> Fut + Send + 'static, ) -> Task where R: Send + 'static, Fut: Future + Send + 'static, { - let handle = self.view(); + let view = self.view(); self.window_cx.spawn(move |_, cx| { - let result = f(handle, cx); + let result = f(view, cx); async move { result.await } }) } @@ -1720,7 +1734,7 @@ where V::Event: Any + Send, { pub fn emit(&mut self, event: V::Event) { - let emitter = self.view.entity_id; + let emitter = self.view.state.entity_id; self.app.push_effect(Effect::Emit { emitter, event: Box::new(event), @@ -1751,6 +1765,30 @@ impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> { } } +impl VisualContext for ViewContext<'_, '_, V> { + type ViewContext<'a, 'w, V2> = ViewContext<'a, 'w, V2>; + + fn build_view( + &mut self, + build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V2>) -> V2, + render: impl Fn(&mut V2, &mut ViewContext<'_, '_, V2>) -> E + Send + 'static, + ) -> Self::Result> + where + E: crate::Component, + V2: 'static + Send, + { + self.window_cx.build_view(build_entity, render) + } + + fn update_view( + &mut self, + view: &View, + update: impl FnOnce(&mut V2, &mut Self::ViewContext<'_, '_, V2>) -> R, + ) -> Self::Result { + self.window_cx.update_view(view, update) + } +} + impl<'a, 'w, V> std::ops::Deref for ViewContext<'a, 'w, V> { type Target = WindowContext<'a, 'w>; diff --git a/crates/storybook2/src/stories/focus.rs b/crates/storybook2/src/stories/focus.rs index 29b061adbaf7f833a426f7b54791e5aac52de2bb..aeb0a243b25c2bb8c7ebc2362ccd83c53004ae0a 100644 --- a/crates/storybook2/src/stories/focus.rs +++ b/crates/storybook2/src/stories/focus.rs @@ -1,6 +1,6 @@ use crate::themes::rose_pine; use gpui2::{ - div, view, Context, Focusable, KeyBinding, ParentElement, StatelessInteractive, Styled, View, + div, Focusable, KeyBinding, ParentElement, StatelessInteractive, Styled, View, VisualContext, WindowContext, }; use serde::Deserialize; @@ -35,80 +35,83 @@ impl FocusStory { let color_4 = theme.lowest.accent.default.foreground; let color_5 = theme.lowest.variant.default.foreground; let color_6 = theme.highest.negative.default.foreground; - let child_1 = cx.focus_handle(); let child_2 = cx.focus_handle(); - view(cx.entity(|cx| ()), move |_, cx| { - div() - .id("parent") - .focusable() - .context("parent") - .on_action(|_, action: &ActionA, phase, cx| { - println!("Action A dispatched on parent during {:?}", phase); - }) - .on_action(|_, action: &ActionB, phase, cx| { - println!("Action B dispatched on parent during {:?}", phase); - }) - .on_focus(|_, _, _| println!("Parent focused")) - .on_blur(|_, _, _| println!("Parent blurred")) - .on_focus_in(|_, _, _| println!("Parent focus_in")) - .on_focus_out(|_, _, _| println!("Parent focus_out")) - .on_key_down(|_, event, phase, _| { - println!("Key down on parent {:?} {:?}", phase, event) - }) - .on_key_up(|_, event, phase, _| { - println!("Key up on parent {:?} {:?}", phase, event) - }) - .size_full() - .bg(color_1) - .focus(|style| style.bg(color_2)) - .focus_in(|style| style.bg(color_3)) - .child( - div() - .track_focus(&child_1) - .context("child-1") - .on_action(|_, action: &ActionB, phase, cx| { - println!("Action B dispatched on child 1 during {:?}", phase); - }) - .w_full() - .h_6() - .bg(color_4) - .focus(|style| style.bg(color_5)) - .in_focus(|style| style.bg(color_6)) - .on_focus(|_, _, _| println!("Child 1 focused")) - .on_blur(|_, _, _| println!("Child 1 blurred")) - .on_focus_in(|_, _, _| println!("Child 1 focus_in")) - .on_focus_out(|_, _, _| println!("Child 1 focus_out")) - .on_key_down(|_, event, phase, _| { - println!("Key down on child 1 {:?} {:?}", phase, event) - }) - .on_key_up(|_, event, phase, _| { - println!("Key up on child 1 {:?} {:?}", phase, event) - }) - .child("Child 1"), - ) - .child( - div() - .track_focus(&child_2) - .context("child-2") - .on_action(|_, action: &ActionC, phase, cx| { - println!("Action C dispatched on child 2 during {:?}", phase); - }) - .w_full() - .h_6() - .bg(color_4) - .on_focus(|_, _, _| println!("Child 2 focused")) - .on_blur(|_, _, _| println!("Child 2 blurred")) - .on_focus_in(|_, _, _| println!("Child 2 focus_in")) - .on_focus_out(|_, _, _| println!("Child 2 focus_out")) - .on_key_down(|_, event, phase, _| { - println!("Key down on child 2 {:?} {:?}", phase, event) - }) - .on_key_up(|_, event, phase, _| { - println!("Key up on child 2 {:?} {:?}", phase, event) - }) - .child("Child 2"), - ) - }) + + cx.build_view( + |_| (), + move |_, cx| { + div() + .id("parent") + .focusable() + .context("parent") + .on_action(|_, action: &ActionA, phase, cx| { + println!("Action A dispatched on parent during {:?}", phase); + }) + .on_action(|_, action: &ActionB, phase, cx| { + println!("Action B dispatched on parent during {:?}", phase); + }) + .on_focus(|_, _, _| println!("Parent focused")) + .on_blur(|_, _, _| println!("Parent blurred")) + .on_focus_in(|_, _, _| println!("Parent focus_in")) + .on_focus_out(|_, _, _| println!("Parent focus_out")) + .on_key_down(|_, event, phase, _| { + println!("Key down on parent {:?} {:?}", phase, event) + }) + .on_key_up(|_, event, phase, _| { + println!("Key up on parent {:?} {:?}", phase, event) + }) + .size_full() + .bg(color_1) + .focus(|style| style.bg(color_2)) + .focus_in(|style| style.bg(color_3)) + .child( + div() + .track_focus(&child_1) + .context("child-1") + .on_action(|_, action: &ActionB, phase, cx| { + println!("Action B dispatched on child 1 during {:?}", phase); + }) + .w_full() + .h_6() + .bg(color_4) + .focus(|style| style.bg(color_5)) + .in_focus(|style| style.bg(color_6)) + .on_focus(|_, _, _| println!("Child 1 focused")) + .on_blur(|_, _, _| println!("Child 1 blurred")) + .on_focus_in(|_, _, _| println!("Child 1 focus_in")) + .on_focus_out(|_, _, _| println!("Child 1 focus_out")) + .on_key_down(|_, event, phase, _| { + println!("Key down on child 1 {:?} {:?}", phase, event) + }) + .on_key_up(|_, event, phase, _| { + println!("Key up on child 1 {:?} {:?}", phase, event) + }) + .child("Child 1"), + ) + .child( + div() + .track_focus(&child_2) + .context("child-2") + .on_action(|_, action: &ActionC, phase, cx| { + println!("Action C dispatched on child 2 during {:?}", phase); + }) + .w_full() + .h_6() + .bg(color_4) + .on_focus(|_, _, _| println!("Child 2 focused")) + .on_blur(|_, _, _| println!("Child 2 blurred")) + .on_focus_in(|_, _, _| println!("Child 2 focus_in")) + .on_focus_out(|_, _, _| println!("Child 2 focus_out")) + .on_key_down(|_, event, phase, _| { + println!("Key down on child 2 {:?} {:?}", phase, event) + }) + .on_key_up(|_, event, phase, _| { + println!("Key up on child 2 {:?} {:?}", phase, event) + }) + .child("Child 2"), + ) + }, + ) } } diff --git a/crates/storybook2/src/stories/kitchen_sink.rs b/crates/storybook2/src/stories/kitchen_sink.rs index ec89238ac45ef68a51e9e3a69545248112a8f697..3a4b127b554f4ffe593c9171116997a1d9cb9556 100644 --- a/crates/storybook2/src/stories/kitchen_sink.rs +++ b/crates/storybook2/src/stories/kitchen_sink.rs @@ -1,4 +1,4 @@ -use gpui2::{view, Context, View}; +use gpui2::{AppContext, Context, View}; use strum::IntoEnumIterator; use ui::prelude::*; @@ -12,8 +12,12 @@ impl KitchenSinkStory { Self {} } - pub fn view(cx: &mut WindowContext) -> View { - view(cx.entity(|cx| Self::new()), Self::render) + pub fn view(cx: &mut AppContext) -> View { + { + let state = cx.entity(|cx| Self::new()); + let render = Self::render; + View::for_handle(state, render) + } } fn render(&mut self, cx: &mut ViewContext) -> impl Component { diff --git a/crates/storybook2/src/stories/scroll.rs b/crates/storybook2/src/stories/scroll.rs index a1e3c6700e4ac47646467d0e9ffb8cf495a5a90f..662d44328b11a6a1af8d5f39db3ab5863bf4cdd5 100644 --- a/crates/storybook2/src/stories/scroll.rs +++ b/crates/storybook2/src/stories/scroll.rs @@ -1,6 +1,6 @@ use crate::themes::rose_pine; use gpui2::{ - div, px, view, Component, Context, ParentElement, SharedString, Styled, View, WindowContext, + div, px, Component, ParentElement, SharedString, Styled, View, VisualContext, WindowContext, }; pub struct ScrollStory { @@ -11,7 +11,9 @@ impl ScrollStory { pub fn view(cx: &mut WindowContext) -> View<()> { let theme = rose_pine(); - view(cx.entity(|cx| ()), move |_, cx| checkerboard(1)) + { + cx.build_view(|cx| (), move |_, cx| checkerboard(1)) + } } } diff --git a/crates/storybook2/src/stories/text.rs b/crates/storybook2/src/stories/text.rs index d66b5ce6092f89e3ca1e90c1fc476b47fb3e7a17..20e109cfa06f5d7a62e6a841a3df0daff9eb9fe9 100644 --- a/crates/storybook2/src/stories/text.rs +++ b/crates/storybook2/src/stories/text.rs @@ -1,4 +1,4 @@ -use gpui2::{div, view, white, Context, ParentElement, Styled, View, WindowContext}; +use gpui2::{div, white, ParentElement, Styled, View, VisualContext, WindowContext}; pub struct TextStory { text: View<()>, @@ -6,7 +6,7 @@ pub struct TextStory { impl TextStory { pub fn view(cx: &mut WindowContext) -> View<()> { - view(cx.entity(|cx| ()), |_, cx| { + cx.build_view(|cx| (), |_, cx| { div() .size_full() .bg(white()) diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook2/src/story_selector.rs index ed6822cb1140ce66121b340304c51976c8518cb4..d6ff77c5c1c4ff183e4921ecc53ac7761e59dadd 100644 --- a/crates/storybook2/src/story_selector.rs +++ b/crates/storybook2/src/story_selector.rs @@ -5,7 +5,7 @@ use crate::stories::*; use anyhow::anyhow; use clap::builder::PossibleValue; use clap::ValueEnum; -use gpui2::{view, AnyView, Context}; +use gpui2::{AnyView, VisualContext}; use strum::{EnumIter, EnumString, IntoEnumIterator}; use ui::prelude::*; @@ -27,16 +27,18 @@ pub enum ElementStory { impl ElementStory { pub fn story(&self, cx: &mut WindowContext) -> AnyView { match self { - Self::Avatar => view(cx.entity(|cx| ()), |_, _| ui::AvatarStory.render()).into_any(), - Self::Button => view(cx.entity(|cx| ()), |_, _| ui::ButtonStory.render()).into_any(), - Self::Details => view(cx.entity(|cx| ()), |_, _| ui::DetailsStory.render()).into_any(), + Self::Avatar => { cx.build_view(|cx| (), |_, _| ui::AvatarStory.render()) }.into_any(), + Self::Button => { cx.build_view(|cx| (), |_, _| ui::ButtonStory.render()) }.into_any(), + Self::Details => { + { cx.build_view(|cx| (), |_, _| ui::DetailsStory.render()) }.into_any() + } Self::Focus => FocusStory::view(cx).into_any(), - Self::Icon => view(cx.entity(|cx| ()), |_, _| ui::IconStory.render()).into_any(), - Self::Input => view(cx.entity(|cx| ()), |_, _| ui::InputStory.render()).into_any(), - Self::Label => view(cx.entity(|cx| ()), |_, _| ui::LabelStory.render()).into_any(), + Self::Icon => { cx.build_view(|cx| (), |_, _| ui::IconStory.render()) }.into_any(), + Self::Input => { cx.build_view(|cx| (), |_, _| ui::InputStory.render()) }.into_any(), + Self::Label => { cx.build_view(|cx| (), |_, _| ui::LabelStory.render()) }.into_any(), Self::Scroll => ScrollStory::view(cx).into_any(), Self::Text => TextStory::view(cx).into_any(), - Self::ZIndex => view(cx.entity(|cx| ()), |_, _| ZIndexStory.render()).into_any(), + Self::ZIndex => { cx.build_view(|cx| (), |_, _| ZIndexStory.render()) }.into_any(), } } } @@ -76,65 +78,67 @@ impl ComponentStory { pub fn story(&self, cx: &mut WindowContext) -> AnyView { match self { Self::AssistantPanel => { - view(cx.entity(|cx| ()), |_, _| ui::AssistantPanelStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::AssistantPanelStory.render()) }.into_any() } - Self::Buffer => view(cx.entity(|cx| ()), |_, _| ui::BufferStory.render()).into_any(), + Self::Buffer => { cx.build_view(|cx| (), |_, _| ui::BufferStory.render()) }.into_any(), Self::Breadcrumb => { - view(cx.entity(|cx| ()), |_, _| ui::BreadcrumbStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::BreadcrumbStory.render()) }.into_any() } Self::ChatPanel => { - view(cx.entity(|cx| ()), |_, _| ui::ChatPanelStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::ChatPanelStory.render()) }.into_any() } Self::CollabPanel => { - view(cx.entity(|cx| ()), |_, _| ui::CollabPanelStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::CollabPanelStory.render()) }.into_any() } Self::CommandPalette => { - view(cx.entity(|cx| ()), |_, _| ui::CommandPaletteStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::CommandPaletteStory.render()) }.into_any() } Self::ContextMenu => { - view(cx.entity(|cx| ()), |_, _| ui::ContextMenuStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::ContextMenuStory.render()) }.into_any() } Self::Facepile => { - view(cx.entity(|cx| ()), |_, _| ui::FacepileStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::FacepileStory.render()) }.into_any() } Self::Keybinding => { - view(cx.entity(|cx| ()), |_, _| ui::KeybindingStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::KeybindingStory.render()) }.into_any() + } + Self::LanguageSelector => { + { cx.build_view(|cx| (), |_, _| ui::LanguageSelectorStory.render()) }.into_any() } - Self::LanguageSelector => view(cx.entity(|cx| ()), |_, _| { - ui::LanguageSelectorStory.render() - }) - .into_any(), Self::MultiBuffer => { - view(cx.entity(|cx| ()), |_, _| ui::MultiBufferStory.render()).into_any() - } - Self::NotificationsPanel => view(cx.entity(|cx| ()), |_, _| { - ui::NotificationsPanelStory.render() - }) - .into_any(), - Self::Palette => view(cx.entity(|cx| ()), |_, _| ui::PaletteStory.render()).into_any(), - Self::Panel => view(cx.entity(|cx| ()), |_, _| ui::PanelStory.render()).into_any(), + { cx.build_view(|cx| (), |_, _| ui::MultiBufferStory.render()) }.into_any() + } + Self::NotificationsPanel => { + { cx.build_view(|cx| (), |_, _| ui::NotificationsPanelStory.render()) }.into_any() + } + Self::Palette => { + { cx.build_view(|cx| (), |_, _| ui::PaletteStory.render()) }.into_any() + } + Self::Panel => { cx.build_view(|cx| (), |_, _| ui::PanelStory.render()) }.into_any(), Self::ProjectPanel => { - view(cx.entity(|cx| ()), |_, _| ui::ProjectPanelStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::ProjectPanelStory.render()) }.into_any() } Self::RecentProjects => { - view(cx.entity(|cx| ()), |_, _| ui::RecentProjectsStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::RecentProjectsStory.render()) }.into_any() } - Self::Tab => view(cx.entity(|cx| ()), |_, _| ui::TabStory.render()).into_any(), - Self::TabBar => view(cx.entity(|cx| ()), |_, _| ui::TabBarStory.render()).into_any(), + Self::Tab => { cx.build_view(|cx| (), |_, _| ui::TabStory.render()) }.into_any(), + Self::TabBar => { cx.build_view(|cx| (), |_, _| ui::TabBarStory.render()) }.into_any(), Self::Terminal => { - view(cx.entity(|cx| ()), |_, _| ui::TerminalStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::TerminalStory.render()) }.into_any() } Self::ThemeSelector => { - view(cx.entity(|cx| ()), |_, _| ui::ThemeSelectorStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::ThemeSelectorStory.render()) }.into_any() } Self::TitleBar => ui::TitleBarStory::view(cx).into_any(), - Self::Toast => view(cx.entity(|cx| ()), |_, _| ui::ToastStory.render()).into_any(), - Self::Toolbar => view(cx.entity(|cx| ()), |_, _| ui::ToolbarStory.render()).into_any(), + Self::Toast => { cx.build_view(|cx| (), |_, _| ui::ToastStory.render()) }.into_any(), + Self::Toolbar => { + { cx.build_view(|cx| (), |_, _| ui::ToolbarStory.render()) }.into_any() + } Self::TrafficLights => { - view(cx.entity(|cx| ()), |_, _| ui::TrafficLightsStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::TrafficLightsStory.render()) }.into_any() } Self::Copilot => { - view(cx.entity(|cx| ()), |_, _| ui::CopilotModalStory.render()).into_any() + { cx.build_view(|cx| (), |_, _| ui::CopilotModalStory.render()) }.into_any() } Self::Workspace => ui::WorkspaceStory::view(cx).into_any(), } diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs index 29ff5eaa9801e98f776f17550b851bba4a4b518b..a06a1392b239723e9838e7d06549ba37d44af6dd 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -10,7 +10,7 @@ use std::sync::Arc; use clap::Parser; use gpui2::{ - div, px, size, view, AnyView, AppContext, Bounds, Context, ViewContext, WindowBounds, + div, px, size, AnyView, AppContext, Bounds, ViewContext, VisualContext, WindowBounds, WindowOptions, }; use log::LevelFilter; @@ -85,8 +85,8 @@ fn main() { ..Default::default() }, move |cx| { - view( - cx.entity(|cx| StoryWrapper::new(selector.story(cx), theme)), + cx.build_view( + |cx| StoryWrapper::new(selector.story(cx), theme), StoryWrapper::render, ) }, diff --git a/crates/ui2/src/components/buffer_search.rs b/crates/ui2/src/components/buffer_search.rs index b5e74a481004b9373710ecafd90b51df7654760d..fa7f752ffee38fb0af80b7c8f15e229ee618c100 100644 --- a/crates/ui2/src/components/buffer_search.rs +++ b/crates/ui2/src/components/buffer_search.rs @@ -1,4 +1,4 @@ -use gpui2::{view, Context, View}; +use gpui2::{AppContext, Context, View}; use crate::prelude::*; use crate::{h_stack, Icon, IconButton, IconColor, Input}; @@ -21,8 +21,12 @@ impl BufferSearch { cx.notify(); } - pub fn view(cx: &mut WindowContext) -> View { - view(cx.entity(|cx| Self::new()), Self::render) + pub fn view(cx: &mut AppContext) -> View { + { + let state = cx.entity(|cx| Self::new()); + let render = Self::render; + View::for_handle(state, render) + } } fn render(&mut self, cx: &mut ViewContext) -> impl Component { diff --git a/crates/ui2/src/components/editor_pane.rs b/crates/ui2/src/components/editor_pane.rs index 9c9638d0579f89e430353816a96c1cab1b2f1613..ec73bb805f1888ee61c9f69300e1bf4b62543dd0 100644 --- a/crates/ui2/src/components/editor_pane.rs +++ b/crates/ui2/src/components/editor_pane.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use gpui2::{view, Context, View}; +use gpui2::{AppContext, Context, View}; use crate::prelude::*; use crate::{ @@ -20,7 +20,7 @@ pub struct EditorPane { impl EditorPane { pub fn new( - cx: &mut WindowContext, + cx: &mut AppContext, tabs: Vec, path: PathBuf, symbols: Vec, @@ -42,11 +42,12 @@ impl EditorPane { cx.notify(); } - pub fn view(cx: &mut WindowContext) -> View { - view( - cx.entity(|cx| hello_world_rust_editor_with_status_example(cx)), - Self::render, - ) + pub fn view(cx: &mut AppContext) -> View { + { + let state = cx.entity(|cx| hello_world_rust_editor_with_status_example(cx)); + let render = Self::render; + View::for_handle(state, render) + } } fn render(&mut self, cx: &mut ViewContext) -> impl Component { diff --git a/crates/ui2/src/components/title_bar.rs b/crates/ui2/src/components/title_bar.rs index 2d080ac649dafa3dcc908be9e86d7c3ffc4ae6c8..11dd1b99f669eb65a67df7f66c3d36ec2d9ad87e 100644 --- a/crates/ui2/src/components/title_bar.rs +++ b/crates/ui2/src/components/title_bar.rs @@ -1,7 +1,7 @@ use std::sync::atomic::AtomicBool; use std::sync::Arc; -use gpui2::{view, Context, View}; +use gpui2::{AppContext, Context, ModelContext, View}; use crate::prelude::*; use crate::settings::user_settings; @@ -28,7 +28,7 @@ pub struct TitleBar { } impl TitleBar { - pub fn new(cx: &mut ViewContext) -> Self { + pub fn new(cx: &mut ModelContext) -> Self { let is_active = Arc::new(AtomicBool::new(true)); let active = is_active.clone(); @@ -80,11 +80,12 @@ impl TitleBar { cx.notify(); } - pub fn view(cx: &mut WindowContext, livestream: Option) -> View { - view( - cx.entity(|cx| Self::new(cx).set_livestream(livestream)), - Self::render, - ) + pub fn view(cx: &mut AppContext, livestream: Option) -> View { + { + let state = cx.entity(|cx| Self::new(cx).set_livestream(livestream)); + let render = Self::render; + View::for_handle(state, render) + } } fn render(&mut self, cx: &mut ViewContext) -> impl Component { @@ -195,13 +196,14 @@ mod stories { } impl TitleBarStory { - pub fn view(cx: &mut WindowContext) -> View { - view( - cx.entity(|cx| Self { + pub fn view(cx: &mut AppContext) -> View { + { + let state = cx.entity(|cx| Self { title_bar: TitleBar::view(cx, None), - }), - Self::render, - ) + }); + let render = Self::render; + View::for_handle(state, render) + } } fn render(&mut self, cx: &mut ViewContext) -> impl Component { diff --git a/crates/ui2/src/components/workspace.rs b/crates/ui2/src/components/workspace.rs index e979de6d7c9db94f5938a4e340890f83d2524fe4..fbb2c6466887a114f4b4a8aa959084879d88cf60 100644 --- a/crates/ui2/src/components/workspace.rs +++ b/crates/ui2/src/components/workspace.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use chrono::DateTime; -use gpui2::{px, relative, rems, view, Context, Size, View}; +use gpui2::{px, relative, rems, AppContext, Context, Size, View}; use crate::{ old_theme, static_livestream, user_settings_mut, v_stack, AssistantPanel, Button, ChatMessage, @@ -44,7 +44,7 @@ pub struct Workspace { } impl Workspace { - pub fn new(cx: &mut ViewContext) -> Self { + pub fn new(cx: &mut AppContext) -> Self { Self { title_bar: TitleBar::view(cx, None), editor_1: EditorPane::view(cx), @@ -170,8 +170,12 @@ impl Workspace { cx.notify(); } - pub fn view(cx: &mut WindowContext) -> View { - view(cx.entity(|cx| Self::new(cx)), Self::render) + pub fn view(cx: &mut AppContext) -> View { + { + let state = cx.entity(|cx| Self::new(cx)); + let render = Self::render; + View::for_handle(state, render) + } } pub fn render(&mut self, cx: &mut ViewContext) -> impl Component { @@ -351,6 +355,8 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::VisualContext; + use super::*; pub struct WorkspaceStory { @@ -359,10 +365,10 @@ mod stories { impl WorkspaceStory { pub fn view(cx: &mut WindowContext) -> View { - view( - cx.entity(|cx| Self { + cx.build_view( + |cx| Self { workspace: Workspace::view(cx), - }), + }, |view, cx| view.workspace.clone(), ) } diff --git a/crates/ui2/src/static_data.rs b/crates/ui2/src/static_data.rs index b315bc1f2a85e7af2e8c173e95dced930831baac..72407b6678b7eddd805fda5eb69bdc9022adee78 100644 --- a/crates/ui2/src/static_data.rs +++ b/crates/ui2/src/static_data.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use std::str::FromStr; -use gpui2::WindowContext; +use gpui2::{AppContext, WindowContext}; use rand::Rng; use theme2::Theme; @@ -781,7 +781,7 @@ pub fn hello_world_rust_buffer_rows(theme: &Theme) -> Vec { ] } -pub fn hello_world_rust_editor_with_status_example(cx: &mut WindowContext) -> EditorPane { +pub fn hello_world_rust_editor_with_status_example(cx: &mut AppContext) -> EditorPane { let theme = theme(cx); EditorPane::new( diff --git a/crates/ui2/src/theme.rs b/crates/ui2/src/theme.rs index e5075c912fe7dabcc6e38372e5f7094d83aaa375..cc46ddcb17bce6467ff47c061eb611f17b08e879 100644 --- a/crates/ui2/src/theme.rs +++ b/crates/ui2/src/theme.rs @@ -1,6 +1,6 @@ use gpui2::{ - AnyElement, Bounds, Component, Element, Hsla, LayoutId, Pixels, Result, ViewContext, - WindowContext, + AnyElement, AppContext, Bounds, Component, Element, Hsla, LayoutId, Pixels, Result, + ViewContext, WindowContext, }; use serde::{de::Visitor, Deserialize, Deserializer}; use std::collections::HashMap; @@ -220,6 +220,6 @@ pub fn old_theme(cx: &WindowContext) -> Arc { Arc::new(cx.global::().clone()) } -pub fn theme(cx: &WindowContext) -> Arc { +pub fn theme(cx: &AppContext) -> Arc { theme2::active_theme(cx).clone() }