From 30dffbb40902668d5687f2599a203801c9ee9901 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 30 Oct 2023 15:19:40 -0700 Subject: [PATCH] Introduce a Render trait, make views implement it Don't pass a render function separately from the view. Co-authored-by: Nathan Sobo Co-authored-by: Mikayla Co-authored-by: Antonio --- crates/gpui2/src/app.rs | 5 +- crates/gpui2/src/app/entity_map.rs | 11 +- crates/gpui2/src/gpui2.rs | 33 ++-- crates/gpui2/src/interactive.rs | 72 ++++----- crates/gpui2/src/view.rs | 41 ++++- crates/gpui2/src/window.rs | 56 +++---- crates/storybook2/src/stories/focus.rs | 149 +++++++++--------- crates/storybook2/src/stories/kitchen_sink.rs | 27 ++-- crates/storybook2/src/stories/scroll.rs | 86 +++++----- crates/storybook2/src/stories/text.rs | 31 ++-- crates/storybook2/src/stories/z_index.rs | 9 +- crates/storybook2/src/story_selector.rs | 104 ++++-------- crates/storybook2/src/storybook2.rs | 17 +- crates/ui2/src/components/assistant_panel.rs | 15 +- crates/ui2/src/components/breadcrumb.rs | 18 +-- crates/ui2/src/components/buffer.rs | 13 +- crates/ui2/src/components/buffer_search.rs | 16 +- crates/ui2/src/components/chat_panel.rs | 8 +- crates/ui2/src/components/collab_panel.rs | 11 +- crates/ui2/src/components/command_palette.rs | 9 +- crates/ui2/src/components/context_menu.rs | 11 +- crates/ui2/src/components/copilot.rs | 9 +- crates/ui2/src/components/editor_pane.rs | 18 +-- crates/ui2/src/components/facepile.rs | 11 +- crates/ui2/src/components/keybinding.rs | 14 +- .../ui2/src/components/language_selector.rs | 11 +- crates/ui2/src/components/multi_buffer.rs | 11 +- .../ui2/src/components/notifications_panel.rs | 11 +- crates/ui2/src/components/palette.rs | 101 ++++++------ crates/ui2/src/components/panel.rs | 13 +- crates/ui2/src/components/panes.rs | 13 +- crates/ui2/src/components/project_panel.rs | 11 +- crates/ui2/src/components/recent_projects.rs | 11 +- crates/ui2/src/components/tab.rs | 31 ++-- crates/ui2/src/components/tab_bar.rs | 11 +- crates/ui2/src/components/terminal.rs | 12 +- crates/ui2/src/components/theme_selector.rs | 9 +- crates/ui2/src/components/title_bar.rs | 39 +++-- crates/ui2/src/components/toast.rs | 11 +- crates/ui2/src/components/toolbar.rs | 11 +- crates/ui2/src/components/traffic_lights.rs | 9 +- crates/ui2/src/components/workspace.rs | 38 +++-- crates/ui2/src/elements/avatar.rs | 11 +- crates/ui2/src/elements/button.rs | 17 +- crates/ui2/src/elements/details.rs | 13 +- crates/ui2/src/elements/icon.rs | 10 +- crates/ui2/src/elements/input.rs | 11 +- crates/ui2/src/elements/label.rs | 11 +- crates/ui2/src/static_data.rs | 8 +- 49 files changed, 616 insertions(+), 612 deletions(-) diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 0523609db3..1d2c17d357 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -898,11 +898,8 @@ impl DerefMut for GlobalLease { /// Contains state associated with an active drag operation, started by dragging an element /// within the window or by dragging into the app from the underlying platform. pub(crate) struct AnyDrag { - pub render: Box AnyElement<()>>, - pub drag_handle_view: Option, + pub view: AnyView, pub cursor_offset: Point, - pub state: AnyBox, - pub state_type: TypeId, } #[cfg(test)] diff --git a/crates/gpui2/src/app/entity_map.rs b/crates/gpui2/src/app/entity_map.rs index bfd457e4ff..7e0c5626a5 100644 --- a/crates/gpui2/src/app/entity_map.rs +++ b/crates/gpui2/src/app/entity_map.rs @@ -147,7 +147,7 @@ pub struct Slot(Model); pub struct AnyModel { pub(crate) entity_id: EntityId, - entity_type: TypeId, + pub(crate) entity_type: TypeId, entity_map: Weak>, } @@ -247,8 +247,8 @@ impl Eq for AnyModel {} pub struct Model { #[deref] #[deref_mut] - any_model: AnyModel, - entity_type: PhantomData, + pub(crate) any_model: AnyModel, + pub(crate) entity_type: PhantomData, } unsafe impl Send for Model {} @@ -272,6 +272,11 @@ impl Model { } } + /// Convert this into a dynamically typed model. + pub fn into_any(self) -> AnyModel { + self.any_model + } + pub fn read<'a>(&self, cx: &'a AppContext) -> &'a T { cx.entities.read(self) } diff --git a/crates/gpui2/src/gpui2.rs b/crates/gpui2/src/gpui2.rs index d85d1e0c74..85300c1a4a 100644 --- a/crates/gpui2/src/gpui2.rs +++ b/crates/gpui2/src/gpui2.rs @@ -90,13 +90,11 @@ pub trait Context { pub trait VisualContext: Context { type ViewContext<'a, 'w, V>; - fn build_view( + fn build_view( &mut self, - build_model: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, - render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, + build_view_state: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, ) -> Self::Result> where - E: Component, V: 'static + Send; fn update_view( @@ -171,27 +169,22 @@ impl Context for MainThread { impl VisualContext for MainThread { type ViewContext<'a, 'w, V> = MainThread>; - fn build_view( + fn build_view( &mut self, - build_model: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, - render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, + build_view_state: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, ) -> 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_model(cx) - }, - render, - ) + self.0.build_view(|cx| { + let cx = unsafe { + mem::transmute::< + &mut C::ViewContext<'_, '_, V>, + &mut MainThread>, + >(cx) + }; + build_view_state(cx) + }) } fn update_view( diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index 43fd83a55f..317d7cea61 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -1,7 +1,7 @@ use crate::{ - point, px, Action, AnyBox, AnyDrag, AppContext, BorrowWindow, Bounds, Component, - DispatchContext, DispatchPhase, Element, ElementId, FocusHandle, KeyMatch, Keystroke, - Modifiers, Overflow, Pixels, Point, SharedString, Size, Style, StyleRefinement, View, + div, point, px, Action, AnyDrag, AnyView, AppContext, BorrowWindow, Bounds, Component, + DispatchContext, DispatchPhase, Div, Element, ElementId, FocusHandle, KeyMatch, Keystroke, + Modifiers, Overflow, Pixels, Point, Render, SharedString, Size, Style, StyleRefinement, View, ViewContext, }; use collections::HashMap; @@ -258,17 +258,17 @@ pub trait StatelessInteractive: Element { self } - fn on_drop( + fn on_drop( mut self, - listener: impl Fn(&mut V, S, &mut ViewContext) + Send + 'static, + listener: impl Fn(&mut V, View, &mut ViewContext) + Send + 'static, ) -> Self where Self: Sized, { self.stateless_interaction().drop_listeners.push(( - TypeId::of::(), - Box::new(move |view, drag_state, cx| { - listener(view, *drag_state.downcast().unwrap(), cx); + TypeId::of::(), + Box::new(move |view, dragged_view, cx| { + listener(view, dragged_view.downcast().unwrap(), cx); }), )); self @@ -314,43 +314,22 @@ pub trait StatefulInteractive: StatelessInteractive { self } - fn on_drag( + fn on_drag( mut self, - listener: impl Fn(&mut V, &mut ViewContext) -> Drag + Send + 'static, + listener: impl Fn(&mut V, &mut ViewContext) -> View + Send + 'static, ) -> Self where Self: Sized, - S: Any + Send, - R: Fn(&mut V, &mut ViewContext) -> E, - R: 'static + Send, - E: Component, + W: 'static + Send + Render, { debug_assert!( self.stateful_interaction().drag_listener.is_none(), "calling on_drag more than once on the same element is not supported" ); self.stateful_interaction().drag_listener = - Some(Box::new(move |view_state, cursor_offset, cx| { - let drag = listener(view_state, cx); - let drag_handle_view = Some( - cx.build_view(|cx| DragView { - model: cx.model().upgrade().unwrap(), - drag, - }) - .into_any(), - ); - AnyDrag { - render: { - let view = cx.view(); - Box::new(move |cx| { - view.update(cx, |view, cx| drag.render_drag_handle(view, cx)) - }) - }, - drag_handle_view, - cursor_offset, - state: Box::new(drag.state), - state_type: TypeId::of::(), - } + Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag { + view: listener(view_state, cx).into_any(), + cursor_offset, })); self } @@ -419,7 +398,7 @@ pub trait ElementInteraction: 'static + Send { if let Some(drag) = cx.active_drag.take() { for (state_type, group_drag_style) in &self.as_stateless().group_drag_over_styles { if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) { - if *state_type == drag.state_type + if *state_type == drag.view.entity_type() && group_bounds.contains_point(&mouse_position) { style.refine(&group_drag_style.style); @@ -428,7 +407,8 @@ pub trait ElementInteraction: 'static + Send { } for (state_type, drag_over_style) in &self.as_stateless().drag_over_styles { - if *state_type == drag.state_type && bounds.contains_point(&mouse_position) { + if *state_type == drag.view.entity_type() && bounds.contains_point(&mouse_position) + { style.refine(drag_over_style); } } @@ -516,7 +496,7 @@ pub trait ElementInteraction: 'static + Send { cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| { if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { if let Some(drag_state_type) = - cx.active_drag.as_ref().map(|drag| drag.state_type) + cx.active_drag.as_ref().map(|drag| drag.view.entity_type()) { for (drop_state_type, listener) in &drop_listeners { if *drop_state_type == drag_state_type { @@ -524,7 +504,7 @@ pub trait ElementInteraction: 'static + Send { .active_drag .take() .expect("checked for type drag state type above"); - listener(view, drag.state, cx); + listener(view, drag.view.clone(), cx); cx.notify(); cx.stop_propagation(); } @@ -692,7 +672,7 @@ impl From for StatefulInteraction { } } -type DropListener = dyn Fn(&mut V, AnyBox, &mut ViewContext) + 'static + Send; +type DropListener = dyn Fn(&mut V, AnyView, &mut ViewContext) + 'static + Send; pub struct StatelessInteraction { pub dispatch_context: DispatchContext, @@ -873,7 +853,7 @@ pub struct Drag where R: Fn(&mut V, &mut ViewContext) -> E, V: 'static, - E: Component, + E: Component<()>, { pub state: S, pub render_drag_handle: R, @@ -884,7 +864,7 @@ impl Drag where R: Fn(&mut V, &mut ViewContext) -> E, V: 'static, - E: Component, + E: Component<()>, { pub fn new(state: S, render_drag_handle: R) -> Self { Drag { @@ -1006,6 +986,14 @@ impl Deref for MouseExitEvent { #[derive(Debug, Clone, Default)] pub struct ExternalPaths(pub(crate) SmallVec<[PathBuf; 2]>); +impl Render for ExternalPaths { + type Element = Div; + + fn render(&mut self, _: &mut ViewContext) -> Self::Element { + div() // Intentionally left empty because the platform will render icons for the dragged files + } +} + #[derive(Debug, Clone)] pub enum FileDropEvent { Entered { diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index 630f2f9864..eef5819361 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -1,9 +1,10 @@ use crate::{ - AnyBox, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId, - EntityId, LayoutId, Model, Pixels, Size, ViewContext, VisualContext, WeakModel, WindowContext, + AnyBox, AnyElement, AnyModel, AppContext, AvailableSpace, BorrowWindow, Bounds, Component, + Element, ElementId, EntityId, LayoutId, Model, Pixels, Size, ViewContext, VisualContext, + WeakModel, WindowContext, }; use anyhow::{Context, Result}; -use std::{marker::PhantomData, sync::Arc}; +use std::{any::TypeId, marker::PhantomData, sync::Arc}; pub trait Render: 'static + Sized { type Element: Element + 'static + Send; @@ -38,6 +39,10 @@ impl View { { cx.update_view(self, f) } + + pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V { + self.model.read(cx) + } } impl Clone for View { @@ -178,7 +183,9 @@ impl Element for EraseViewState TypeId; fn entity_id(&self) -> EntityId; + fn model(&self) -> AnyModel; fn initialize(&self, cx: &mut WindowContext) -> AnyBox; fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId; fn paint(&self, bounds: Bounds, element: &mut AnyBox, cx: &mut WindowContext); @@ -188,10 +195,18 @@ impl ViewObject for View where V: Render, { + fn entity_type(&self) -> TypeId { + TypeId::of::() + } + fn entity_id(&self) -> EntityId { self.model.entity_id } + fn model(&self) -> AnyModel { + self.model.clone().into_any() + } + fn initialize(&self, cx: &mut WindowContext) -> AnyBox { cx.with_element_id(self.entity_id(), |_global_id, cx| { self.update(cx, |state, cx| { @@ -225,6 +240,14 @@ where pub struct AnyView(Arc); impl AnyView { + pub fn downcast(self) -> Option> { + self.0.model().downcast().map(|model| View { model }) + } + + pub(crate) fn entity_type(&self) -> TypeId { + self.0.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); @@ -294,6 +317,18 @@ impl Component for EraseAnyViewState { } } +impl Render for T +where + T: 'static + FnMut(&mut WindowContext) -> E, + E: 'static + Send + Element, +{ + type Element = E; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + (self)(cx) + } +} + impl Element for EraseAnyViewState { type ElementState = AnyBox; diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 86732cd21e..d5e18e1439 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1,11 +1,11 @@ use crate::{ px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect, - EntityId, EventEmitter, ExternalPaths, FileDropEvent, FocusEvent, FontId, GlobalElementId, - GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, - LayoutId, MainThread, MainThreadOnly, Model, ModelContext, Modifiers, MonochromeSprite, - MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, - PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams, + EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla, + ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId, + MainThread, MainThreadOnly, Model, 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, WeakModel, WeakView, WindowOptions, SUBPIXEL_VARIANTS, @@ -891,18 +891,13 @@ impl<'a, 'w> WindowContext<'a, 'w> { root_view.draw(available_space, cx); }); - if let Some(mut active_drag) = self.app.active_drag.take() { + if let Some(active_drag) = self.app.active_drag.take() { 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 { - drag_handle_view.draw(available_space, cx); - } - if let Some(render) = &mut active_drag.render { - (render)() - } + active_drag.view.draw(available_space, cx); cx.active_drag = Some(active_drag); }); }); @@ -970,12 +965,12 @@ impl<'a, 'w> WindowContext<'a, 'w> { InputEvent::FileDrop(file_drop) => match file_drop { FileDropEvent::Entered { position, files } => { self.window.mouse_position = position; - self.active_drag.get_or_insert_with(|| AnyDrag { - drag_handle_view: None, - cursor_offset: position, - state: Box::new(files), - state_type: TypeId::of::(), - }); + if self.active_drag.is_none() { + self.active_drag = Some(AnyDrag { + view: self.build_view(|_| files).into_any(), + cursor_offset: position, + }); + } InputEvent::MouseDown(MouseDownEvent { position, button: MouseButton::Left, @@ -1276,21 +1271,17 @@ impl Context for WindowContext<'_, '_> { impl VisualContext for WindowContext<'_, '_> { type ViewContext<'a, 'w, V> = ViewContext<'a, 'w, V>; - /// Builds a new view in the current window. The first argument is a function that builds - /// an entity representing the view's state. It is invoked with a `ViewContext` that provides - /// entity-specific access to the window and application state during construction. The second - /// argument is a render function that returns a component based on the view's state. - fn build_view( + 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 view = View { + model: slot.clone(), + }; 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); @@ -1885,16 +1876,11 @@ 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( + fn build_view( &mut self, - build_view: 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_view, render) + build_view: impl FnOnce(&mut Self::ViewContext<'_, '_, W>) -> W, + ) -> Self::Result> { + self.window_cx.build_view(build_view) } fn update_view( diff --git a/crates/storybook2/src/stories/focus.rs b/crates/storybook2/src/stories/focus.rs index b1db0187d6..f3f6a8d5fb 100644 --- a/crates/storybook2/src/stories/focus.rs +++ b/crates/storybook2/src/stories/focus.rs @@ -1,6 +1,6 @@ use gpui2::{ - div, Focusable, KeyBinding, ParentElement, StatelessInteractive, Styled, View, VisualContext, - WindowContext, + div, Div, FocusEnabled, Focusable, KeyBinding, ParentElement, Render, StatefulInteraction, + StatelessInteractive, Styled, View, VisualContext, WindowContext, }; use serde::Deserialize; use theme2::theme; @@ -14,12 +14,10 @@ struct ActionB; #[derive(Clone, Default, PartialEq, Deserialize)] struct ActionC; -pub struct FocusStory { - text: View<()>, -} +pub struct FocusStory {} impl FocusStory { - pub fn view(cx: &mut WindowContext) -> View<()> { + pub fn view(cx: &mut WindowContext) -> View { cx.bind_keys([ KeyBinding::new("cmd-a", ActionA, Some("parent")), KeyBinding::new("cmd-a", ActionB, Some("child-1")), @@ -27,8 +25,16 @@ impl FocusStory { ]); cx.register_action_type::(); cx.register_action_type::(); - let theme = theme(cx); + cx.build_view(move |cx| Self {}) + } +} + +impl Render for FocusStory { + type Element = Div, FocusEnabled>; + + fn render(&mut self, cx: &mut gpui2::ViewContext) -> Self::Element { + let theme = theme(cx); let color_1 = theme.git_created; let color_2 = theme.git_modified; let color_3 = theme.git_deleted; @@ -38,80 +44,73 @@ impl FocusStory { let child_1 = cx.focus_handle(); let child_2 = cx.focus_handle(); - 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() - .id("parent") - .focusable() - .context("parent") - .on_action(|_, action: &ActionA, phase, cx| { - println!("Action A dispatched on parent during {:?}", phase); - }) + .track_focus(&child_1) + .context("child-1") .on_action(|_, action: &ActionB, phase, cx| { - println!("Action B dispatched on parent during {:?}", phase); + println!("Action B dispatched on child 1 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")) + .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 parent {:?} {:?}", phase, event) + println!("Key down on child 1 {:?} {:?}", phase, event) }) .on_key_up(|_, event, phase, _| { - println!("Key up on parent {:?} {:?}", phase, event) + println!("Key up on child 1 {:?} {:?}", 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"), - ) - }, - ) + .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 406eb33853..cfa91417b6 100644 --- a/crates/storybook2/src/stories/kitchen_sink.rs +++ b/crates/storybook2/src/stories/kitchen_sink.rs @@ -1,26 +1,23 @@ -use gpui2::{AppContext, Context, View}; +use crate::{ + story::Story, + story_selector::{ComponentStory, ElementStory}, +}; +use gpui2::{Div, Render, StatefulInteraction, View, VisualContext}; use strum::IntoEnumIterator; use ui::prelude::*; -use crate::story::Story; -use crate::story_selector::{ComponentStory, ElementStory}; - -pub struct KitchenSinkStory {} +pub struct KitchenSinkStory; impl KitchenSinkStory { - pub fn new() -> Self { - Self {} + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| Self) } +} - pub fn view(cx: &mut AppContext) -> View { - { - let state = cx.build_model(|cx| Self::new()); - let render = Self::render; - View::for_handle(state, render) - } - } +impl Render for KitchenSinkStory { + type Element = Div>; - fn render(&mut self, cx: &mut ViewContext) -> impl Component { + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let element_stories = ElementStory::iter() .map(|selector| selector.story(cx)) .collect::>(); diff --git a/crates/storybook2/src/stories/scroll.rs b/crates/storybook2/src/stories/scroll.rs index 1b8877ef5c..b504a512a6 100644 --- a/crates/storybook2/src/stories/scroll.rs +++ b/crates/storybook2/src/stories/scroll.rs @@ -1,54 +1,54 @@ use gpui2::{ - div, px, Component, ParentElement, SharedString, Styled, View, VisualContext, WindowContext, + div, px, Component, Div, ParentElement, Render, SharedString, StatefulInteraction, Styled, + View, VisualContext, WindowContext, }; use theme2::theme; -pub struct ScrollStory { - text: View<()>, -} +pub struct ScrollStory; impl ScrollStory { - pub fn view(cx: &mut WindowContext) -> View<()> { - cx.build_view(|cx| (), move |_, cx| checkerboard(cx, 1)) + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| ScrollStory) } } -fn checkerboard(cx: &mut WindowContext, depth: usize) -> impl Component -where - S: 'static + Send + Sync, -{ - let theme = theme(cx); - let color_1 = theme.git_created; - let color_2 = theme.git_modified; +impl Render for ScrollStory { + type Element = Div>; - div() - .id("parent") - .bg(theme.background) - .size_full() - .overflow_scroll() - .children((0..10).map(|row| { - div() - .w(px(1000.)) - .h(px(100.)) - .flex() - .flex_row() - .children((0..10).map(|column| { - let id = SharedString::from(format!("{}, {}", row, column)); - let bg = if row % 2 == column % 2 { - color_1 - } else { - color_2 - }; - div().id(id).bg(bg).size(px(100. / depth as f32)).when( - row >= 5 && column >= 5, - |d| { - d.overflow_scroll() - .child(div().size(px(50.)).bg(color_1)) - .child(div().size(px(50.)).bg(color_2)) - .child(div().size(px(50.)).bg(color_1)) - .child(div().size(px(50.)).bg(color_2)) - }, - ) - })) - })) + fn render(&mut self, cx: &mut gpui2::ViewContext) -> Self::Element { + let theme = theme(cx); + let color_1 = theme.git_created; + let color_2 = theme.git_modified; + + div() + .id("parent") + .bg(theme.background) + .size_full() + .overflow_scroll() + .children((0..10).map(|row| { + div() + .w(px(1000.)) + .h(px(100.)) + .flex() + .flex_row() + .children((0..10).map(|column| { + let id = SharedString::from(format!("{}, {}", row, column)); + let bg = if row % 2 == column % 2 { + color_1 + } else { + color_2 + }; + div().id(id).bg(bg).size(px(100. as f32)).when( + row >= 5 && column >= 5, + |d| { + d.overflow_scroll() + .child(div().size(px(50.)).bg(color_1)) + .child(div().size(px(50.)).bg(color_2)) + .child(div().size(px(50.)).bg(color_1)) + .child(div().size(px(50.)).bg(color_2)) + }, + ) + })) + })) + } } diff --git a/crates/storybook2/src/stories/text.rs b/crates/storybook2/src/stories/text.rs index 20e109cfa0..85a9fd51a6 100644 --- a/crates/storybook2/src/stories/text.rs +++ b/crates/storybook2/src/stories/text.rs @@ -1,20 +1,21 @@ -use gpui2::{div, white, ParentElement, Styled, View, VisualContext, WindowContext}; +use gpui2::{div, white, Div, ParentElement, Render, Styled, View, VisualContext, WindowContext}; -pub struct TextStory { - text: View<()>, -} +pub struct TextStory; impl TextStory { - pub fn view(cx: &mut WindowContext) -> View<()> { - cx.build_view(|cx| (), |_, cx| { - div() - .size_full() - .bg(white()) - .child(concat!( - "The quick brown fox jumps over the lazy dog. ", - "Meanwhile, the lazy dog decided it was time for a change. ", - "He started daily workout routines, ate healthier and became the fastest dog in town.", - )) - }) + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| Self) + } +} + +impl Render for TextStory { + type Element = Div; + + fn render(&mut self, cx: &mut gpui2::ViewContext) -> Self::Element { + div().size_full().bg(white()).child(concat!( + "The quick brown fox jumps over the lazy dog. ", + "Meanwhile, the lazy dog decided it was time for a change. ", + "He started daily workout routines, ate healthier and became the fastest dog in town.", + )) } } diff --git a/crates/storybook2/src/stories/z_index.rs b/crates/storybook2/src/stories/z_index.rs index 7584d0b129..c0e1456bc0 100644 --- a/crates/storybook2/src/stories/z_index.rs +++ b/crates/storybook2/src/stories/z_index.rs @@ -1,15 +1,16 @@ -use gpui2::{px, rgb, Div, Hsla}; +use gpui2::{px, rgb, Div, Hsla, Render}; use ui::prelude::*; use crate::story::Story; /// A reimplementation of the MDN `z-index` example, found here: /// [https://developer.mozilla.org/en-US/docs/Web/CSS/z-index](https://developer.mozilla.org/en-US/docs/Web/CSS/z-index). -#[derive(Component)] pub struct ZIndexStory; -impl ZIndexStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { +impl Render for ZIndexStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title(cx, "z-index")) .child( diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook2/src/story_selector.rs index d6ff77c5c1..997e45ead7 100644 --- a/crates/storybook2/src/story_selector.rs +++ b/crates/storybook2/src/story_selector.rs @@ -7,7 +7,7 @@ use clap::builder::PossibleValue; use clap::ValueEnum; use gpui2::{AnyView, VisualContext}; use strum::{EnumIter, EnumString, IntoEnumIterator}; -use ui::prelude::*; +use ui::{prelude::*, AvatarStory, ButtonStory, DetailsStory, IconStory, InputStory, LabelStory}; #[derive(Debug, PartialEq, Eq, Clone, Copy, strum::Display, EnumString, EnumIter)] #[strum(serialize_all = "snake_case")] @@ -27,18 +27,16 @@ pub enum ElementStory { impl ElementStory { pub fn story(&self, cx: &mut WindowContext) -> AnyView { match self { - 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::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(|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::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(|cx| (), |_, _| ZIndexStory.render()) }.into_any(), + Self::ZIndex => cx.build_view(|_| ZIndexStory).into_any(), } } } @@ -77,69 +75,31 @@ pub enum ComponentStory { impl ComponentStory { pub fn story(&self, cx: &mut WindowContext) -> AnyView { match self { - Self::AssistantPanel => { - { cx.build_view(|cx| (), |_, _| ui::AssistantPanelStory.render()) }.into_any() - } - Self::Buffer => { cx.build_view(|cx| (), |_, _| ui::BufferStory.render()) }.into_any(), - Self::Breadcrumb => { - { cx.build_view(|cx| (), |_, _| ui::BreadcrumbStory.render()) }.into_any() - } - Self::ChatPanel => { - { cx.build_view(|cx| (), |_, _| ui::ChatPanelStory.render()) }.into_any() - } - Self::CollabPanel => { - { cx.build_view(|cx| (), |_, _| ui::CollabPanelStory.render()) }.into_any() - } - Self::CommandPalette => { - { cx.build_view(|cx| (), |_, _| ui::CommandPaletteStory.render()) }.into_any() - } - Self::ContextMenu => { - { cx.build_view(|cx| (), |_, _| ui::ContextMenuStory.render()) }.into_any() - } - Self::Facepile => { - { cx.build_view(|cx| (), |_, _| ui::FacepileStory.render()) }.into_any() - } - Self::Keybinding => { - { cx.build_view(|cx| (), |_, _| ui::KeybindingStory.render()) }.into_any() - } - Self::LanguageSelector => { - { cx.build_view(|cx| (), |_, _| ui::LanguageSelectorStory.render()) }.into_any() - } - Self::MultiBuffer => { - { 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 => { - { cx.build_view(|cx| (), |_, _| ui::ProjectPanelStory.render()) }.into_any() - } - Self::RecentProjects => { - { cx.build_view(|cx| (), |_, _| ui::RecentProjectsStory.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 => { - { cx.build_view(|cx| (), |_, _| ui::TerminalStory.render()) }.into_any() - } - Self::ThemeSelector => { - { cx.build_view(|cx| (), |_, _| ui::ThemeSelectorStory.render()) }.into_any() - } + 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::Toast => { cx.build_view(|cx| (), |_, _| ui::ToastStory.render()) }.into_any(), - Self::Toolbar => { - { cx.build_view(|cx| (), |_, _| ui::ToolbarStory.render()) }.into_any() - } - Self::TrafficLights => { - { cx.build_view(|cx| (), |_, _| ui::TrafficLightsStory.render()) }.into_any() - } - Self::Copilot => { - { 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 584a9abe39..c2903c88e1 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -9,8 +9,8 @@ use std::sync::Arc; use clap::Parser; use gpui2::{ - div, px, size, AnyView, AppContext, Bounds, ViewContext, VisualContext, WindowBounds, - WindowOptions, + div, px, size, AnyView, AppContext, Bounds, Div, Render, ViewContext, VisualContext, + WindowBounds, WindowOptions, }; use log::LevelFilter; use settings2::{default_settings, Settings, SettingsStore}; @@ -82,12 +82,7 @@ fn main() { }), ..Default::default() }, - move |cx| { - cx.build_view( - |cx| StoryWrapper::new(selector.story(cx)), - StoryWrapper::render, - ) - }, + move |cx| cx.build_view(|cx| StoryWrapper::new(selector.story(cx))), ); cx.activate(true); @@ -103,8 +98,12 @@ impl StoryWrapper { pub(crate) fn new(story: AnyView) -> Self { Self { story } } +} - fn render(&mut self, cx: &mut ViewContext) -> impl Component { +impl Render for StoryWrapper { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { div() .flex() .flex_col() diff --git a/crates/ui2/src/components/assistant_panel.rs b/crates/ui2/src/components/assistant_panel.rs index 9b2abd5c17..51c123ad9e 100644 --- a/crates/ui2/src/components/assistant_panel.rs +++ b/crates/ui2/src/components/assistant_panel.rs @@ -1,7 +1,6 @@ -use gpui2::{rems, AbsoluteLength}; - use crate::prelude::*; use crate::{Icon, IconButton, Label, Panel, PanelSide}; +use gpui2::{rems, AbsoluteLength}; #[derive(Component)] pub struct AssistantPanel { @@ -76,15 +75,15 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; - - #[derive(Component)] + use crate::Story; + use gpui2::{Div, Render}; pub struct AssistantPanelStory; - impl AssistantPanelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for AssistantPanelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, AssistantPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/breadcrumb.rs b/crates/ui2/src/components/breadcrumb.rs index 4a2cebcb80..6b2dfe1cce 100644 --- a/crates/ui2/src/components/breadcrumb.rs +++ b/crates/ui2/src/components/breadcrumb.rs @@ -73,21 +73,17 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use super::*; + use crate::Story; + use gpui2::Render; use std::str::FromStr; - use crate::Story; - - use super::*; - - #[derive(Component)] pub struct BreadcrumbStory; - impl BreadcrumbStory { - fn render( - self, - view_state: &mut V, - cx: &mut ViewContext, - ) -> impl Component { + impl Render for BreadcrumbStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/buffer.rs b/crates/ui2/src/components/buffer.rs index 5754397719..33a98b6ea9 100644 --- a/crates/ui2/src/components/buffer.rs +++ b/crates/ui2/src/components/buffer.rs @@ -233,20 +233,19 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use gpui2::rems; - + use super::*; use crate::{ empty_buffer_example, hello_world_rust_buffer_example, hello_world_rust_buffer_with_status_example, Story, }; + use gpui2::{rems, Div, Render}; - use super::*; - - #[derive(Component)] pub struct BufferStory; - impl BufferStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for BufferStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/buffer_search.rs b/crates/ui2/src/components/buffer_search.rs index 85a74930ce..c5539f0a4a 100644 --- a/crates/ui2/src/components/buffer_search.rs +++ b/crates/ui2/src/components/buffer_search.rs @@ -1,4 +1,4 @@ -use gpui2::{AppContext, Context, View}; +use gpui2::{Div, Render, View, VisualContext}; use crate::prelude::*; use crate::{h_stack, Icon, IconButton, IconColor, Input}; @@ -21,15 +21,15 @@ impl BufferSearch { cx.notify(); } - pub fn view(cx: &mut AppContext) -> View { - { - let state = cx.build_model(|cx| Self::new()); - let render = Self::render; - View::for_handle(state, render) - } + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| Self::new()) } +} - fn render(&mut self, cx: &mut ViewContext) -> impl Component { +impl Render for BufferSearch { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Div { let theme = theme(cx); h_stack().bg(theme.toolbar).p_2().child( diff --git a/crates/ui2/src/components/chat_panel.rs b/crates/ui2/src/components/chat_panel.rs index d4fddebc1b..f4f1ddf433 100644 --- a/crates/ui2/src/components/chat_panel.rs +++ b/crates/ui2/src/components/chat_panel.rs @@ -108,16 +108,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { use chrono::DateTime; + use gpui2::{Div, Render}; use crate::{Panel, Story}; use super::*; - #[derive(Component)] pub struct ChatPanelStory; - impl ChatPanelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ChatPanelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, ChatPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/collab_panel.rs b/crates/ui2/src/components/collab_panel.rs index d14c1fec1e..a8552c0f23 100644 --- a/crates/ui2/src/components/collab_panel.rs +++ b/crates/ui2/src/components/collab_panel.rs @@ -89,15 +89,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct CollabPanelStory; - impl CollabPanelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for CollabPanelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, CollabPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/command_palette.rs b/crates/ui2/src/components/command_palette.rs index 71ca5bc41b..63db4359e7 100644 --- a/crates/ui2/src/components/command_palette.rs +++ b/crates/ui2/src/components/command_palette.rs @@ -27,15 +27,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; + use crate::Story; use super::*; - #[derive(Component)] pub struct CommandPaletteStory; - impl CommandPaletteStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for CommandPaletteStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, CommandPalette>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index f2a5557f17..812221036a 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -68,15 +68,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::story::Story; - use super::*; + use crate::story::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct ContextMenuStory; - impl ContextMenuStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ContextMenuStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, ContextMenu>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/copilot.rs b/crates/ui2/src/components/copilot.rs index 7a565d0907..51523d48f0 100644 --- a/crates/ui2/src/components/copilot.rs +++ b/crates/ui2/src/components/copilot.rs @@ -25,15 +25,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; + use crate::Story; use super::*; - #[derive(Component)] pub struct CopilotModalStory; - impl CopilotModalStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for CopilotModalStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, CopilotModal>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/editor_pane.rs b/crates/ui2/src/components/editor_pane.rs index 33f9051dc9..8e54d2c2e8 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::{AppContext, Context, View}; +use gpui2::{Div, Render, View, VisualContext}; use crate::prelude::*; use crate::{ @@ -20,7 +20,7 @@ pub struct EditorPane { impl EditorPane { pub fn new( - cx: &mut AppContext, + cx: &mut ViewContext, tabs: Vec, path: PathBuf, symbols: Vec, @@ -42,15 +42,15 @@ impl EditorPane { cx.notify(); } - pub fn view(cx: &mut AppContext) -> View { - { - let state = cx.build_model(|cx| hello_world_rust_editor_with_status_example(cx)); - let render = Self::render; - View::for_handle(state, render) - } + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| hello_world_rust_editor_with_status_example(cx)) } +} - fn render(&mut self, cx: &mut ViewContext) -> impl Component { +impl Render for EditorPane { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Div { v_stack() .w_full() .h_full() diff --git a/crates/ui2/src/components/facepile.rs b/crates/ui2/src/components/facepile.rs index ab1ae47139..21dd848a28 100644 --- a/crates/ui2/src/components/facepile.rs +++ b/crates/ui2/src/components/facepile.rs @@ -31,15 +31,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::{static_players, Story}; - use super::*; + use crate::{static_players, Story}; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct FacepileStory; - impl FacepileStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for FacepileStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let players = static_players(); Story::container(cx) diff --git a/crates/ui2/src/components/keybinding.rs b/crates/ui2/src/components/keybinding.rs index ec29e7a95d..455cfe5b59 100644 --- a/crates/ui2/src/components/keybinding.rs +++ b/crates/ui2/src/components/keybinding.rs @@ -158,17 +158,17 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use super::*; + use crate::Story; + use gpui2::{Div, Render}; use itertools::Itertools; - use crate::Story; - - use super::*; - - #[derive(Component)] pub struct KeybindingStory; - impl KeybindingStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for KeybindingStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let all_modifier_permutations = ModifierKey::iter().permutations(2); Story::container(cx) diff --git a/crates/ui2/src/components/language_selector.rs b/crates/ui2/src/components/language_selector.rs index f75dcf3eaf..fa7f5b2bd7 100644 --- a/crates/ui2/src/components/language_selector.rs +++ b/crates/ui2/src/components/language_selector.rs @@ -38,15 +38,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct LanguageSelectorStory; - impl LanguageSelectorStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for LanguageSelectorStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, LanguageSelector>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/multi_buffer.rs b/crates/ui2/src/components/multi_buffer.rs index e5051fc5b8..696fc77a62 100644 --- a/crates/ui2/src/components/multi_buffer.rs +++ b/crates/ui2/src/components/multi_buffer.rs @@ -40,15 +40,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::{hello_world_rust_buffer_example, Story}; - use super::*; + use crate::{hello_world_rust_buffer_example, Story}; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct MultiBufferStory; - impl MultiBufferStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for MultiBufferStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/notifications_panel.rs b/crates/ui2/src/components/notifications_panel.rs index 68fe6d4bd0..6872f116e9 100644 --- a/crates/ui2/src/components/notifications_panel.rs +++ b/crates/ui2/src/components/notifications_panel.rs @@ -48,15 +48,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::{Panel, Story}; - use super::*; + use crate::{Panel, Story}; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct NotificationsPanelStory; - impl NotificationsPanelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for NotificationsPanelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, NotificationsPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/palette.rs b/crates/ui2/src/components/palette.rs index a74c9e3672..e47f6a4cea 100644 --- a/crates/ui2/src/components/palette.rs +++ b/crates/ui2/src/components/palette.rs @@ -152,58 +152,71 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; + use crate::{ModifierKeys, Story}; use super::*; - #[derive(Component)] pub struct PaletteStory; - impl PaletteStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - Story::container(cx) - .child(Story::title_for::<_, Palette>(cx)) - .child(Story::label(cx, "Default")) - .child(Palette::new("palette-1")) - .child(Story::label(cx, "With Items")) - .child( - Palette::new("palette-2") - .placeholder("Execute a command...") - .items(vec![ - PaletteItem::new("theme selector: toggle").keybinding( - Keybinding::new_chord( - ("k".to_string(), ModifierKeys::new().command(true)), - ("t".to_string(), ModifierKeys::new().command(true)), + impl Render for PaletteStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + { + Story::container(cx) + .child(Story::title_for::<_, Palette>(cx)) + .child(Story::label(cx, "Default")) + .child(Palette::new("palette-1")) + .child(Story::label(cx, "With Items")) + .child( + Palette::new("palette-2") + .placeholder("Execute a command...") + .items(vec![ + PaletteItem::new("theme selector: toggle").keybinding( + Keybinding::new_chord( + ("k".to_string(), ModifierKeys::new().command(true)), + ("t".to_string(), ModifierKeys::new().command(true)), + ), ), - ), - PaletteItem::new("assistant: inline assist").keybinding( - Keybinding::new( - "enter".to_string(), - ModifierKeys::new().command(true), + PaletteItem::new("assistant: inline assist").keybinding( + Keybinding::new( + "enter".to_string(), + ModifierKeys::new().command(true), + ), ), - ), - PaletteItem::new("assistant: quote selection").keybinding( - Keybinding::new(">".to_string(), ModifierKeys::new().command(true)), - ), - PaletteItem::new("assistant: toggle focus").keybinding( - Keybinding::new("?".to_string(), ModifierKeys::new().command(true)), - ), - PaletteItem::new("auto update: check"), - PaletteItem::new("auto update: view release notes"), - PaletteItem::new("branches: open recent").keybinding(Keybinding::new( - "b".to_string(), - ModifierKeys::new().command(true).alt(true), - )), - PaletteItem::new("chat panel: toggle focus"), - PaletteItem::new("cli: install"), - PaletteItem::new("client: sign in"), - PaletteItem::new("client: sign out"), - PaletteItem::new("editor: cancel").keybinding(Keybinding::new( - "escape".to_string(), - ModifierKeys::new(), - )), - ]), - ) + PaletteItem::new("assistant: quote selection").keybinding( + Keybinding::new( + ">".to_string(), + ModifierKeys::new().command(true), + ), + ), + PaletteItem::new("assistant: toggle focus").keybinding( + Keybinding::new( + "?".to_string(), + ModifierKeys::new().command(true), + ), + ), + PaletteItem::new("auto update: check"), + PaletteItem::new("auto update: view release notes"), + PaletteItem::new("branches: open recent").keybinding( + Keybinding::new( + "b".to_string(), + ModifierKeys::new().command(true).alt(true), + ), + ), + PaletteItem::new("chat panel: toggle focus"), + PaletteItem::new("cli: install"), + PaletteItem::new("client: sign in"), + PaletteItem::new("client: sign out"), + PaletteItem::new("editor: cancel").keybinding(Keybinding::new( + "escape".to_string(), + ModifierKeys::new(), + )), + ]), + ) + } } } } diff --git a/crates/ui2/src/components/panel.rs b/crates/ui2/src/components/panel.rs index 40129dbd76..12d2207ffd 100644 --- a/crates/ui2/src/components/panel.rs +++ b/crates/ui2/src/components/panel.rs @@ -128,17 +128,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::{Label, Story}; - use super::*; + use crate::{Label, Story}; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct PanelStory; - impl PanelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for PanelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) - .child(Story::title_for::<_, Panel>(cx)) + .child(Story::title_for::<_, Panel>(cx)) .child(Story::label(cx, "Default")) .child( Panel::new("panel", cx).child( diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index b692872741..854786ebaa 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -1,4 +1,4 @@ -use gpui2::{hsla, red, AnyElement, ElementId, ExternalPaths, Hsla, Length, Size}; +use gpui2::{hsla, red, AnyElement, ElementId, ExternalPaths, Hsla, Length, Size, View}; use smallvec::SmallVec; use crate::prelude::*; @@ -18,13 +18,6 @@ pub struct Pane { children: SmallVec<[AnyElement; 2]>, } -// impl IntoAnyElement for Pane { -// fn into_any(self) -> AnyElement { -// (move |view_state: &mut V, cx: &mut ViewContext<'_, '_, V>| self.render(view_state, cx)) -// .into_any() -// } -// } - impl Pane { pub fn new(id: impl Into, size: Size) -> Self { // Fill is only here for debugging purposes, remove before release @@ -57,8 +50,8 @@ impl Pane { .z_index(1) .id("drag-target") .drag_over::(|d| d.bg(red())) - .on_drop(|_, files: ExternalPaths, _| { - dbg!("dropped files!", files); + .on_drop(|_, files: View, cx| { + dbg!("dropped files!", files.read(cx)); }) .absolute() .inset_0(), diff --git a/crates/ui2/src/components/project_panel.rs b/crates/ui2/src/components/project_panel.rs index 9f15102acc..84c68119fe 100644 --- a/crates/ui2/src/components/project_panel.rs +++ b/crates/ui2/src/components/project_panel.rs @@ -57,15 +57,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::{Panel, Story}; - use super::*; + use crate::{Panel, Story}; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct ProjectPanelStory; - impl ProjectPanelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ProjectPanelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, ProjectPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/recent_projects.rs b/crates/ui2/src/components/recent_projects.rs index cd7c22eecb..d5a9dd1b22 100644 --- a/crates/ui2/src/components/recent_projects.rs +++ b/crates/ui2/src/components/recent_projects.rs @@ -34,15 +34,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct RecentProjectsStory; - impl RecentProjectsStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for RecentProjectsStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, RecentProjects>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/tab.rs b/crates/ui2/src/components/tab.rs index 6133906f27..d784ec0174 100644 --- a/crates/ui2/src/components/tab.rs +++ b/crates/ui2/src/components/tab.rs @@ -1,5 +1,6 @@ use crate::prelude::*; use crate::{Icon, IconColor, IconElement, Label, LabelColor}; +use gpui2::{black, red, Div, ElementId, Render, View, VisualContext}; #[derive(Component, Clone)] pub struct Tab { @@ -19,6 +20,14 @@ struct TabDragState { title: String, } +impl Render for TabDragState { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + div().w_8().h_4().bg(red()) + } +} + impl Tab { pub fn new(id: impl Into) -> Self { Self { @@ -118,12 +127,10 @@ impl Tab { div() .id(self.id.clone()) - .on_drag(move |_view, _cx| { - Drag::new(drag_state.clone(), |view, cx| div().w_8().h_4().bg(red())) - }) + .on_drag(move |_view, cx| cx.build_view(|cx| drag_state.clone())) .drag_over::(|d| d.bg(black())) - .on_drop(|_view, state: TabDragState, cx| { - dbg!(state); + .on_drop(|_view, state: View, cx| { + dbg!(state.read(cx)); }) .px_2() .py_0p5() @@ -160,23 +167,21 @@ impl Tab { } } -use gpui2::{black, red, Drag, ElementId}; #[cfg(feature = "stories")] pub use stories::*; #[cfg(feature = "stories")] mod stories { + use super::*; + use crate::{h_stack, v_stack, Icon, Story}; use strum::IntoEnumIterator; - use crate::{h_stack, v_stack, Icon, Story}; - - use super::*; - - #[derive(Component)] pub struct TabStory; - impl TabStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for TabStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let git_statuses = GitStatus::iter(); let fs_statuses = FileSystemStatus::iter(); diff --git a/crates/ui2/src/components/tab_bar.rs b/crates/ui2/src/components/tab_bar.rs index cffdc09026..da0a41a1bf 100644 --- a/crates/ui2/src/components/tab_bar.rs +++ b/crates/ui2/src/components/tab_bar.rs @@ -92,15 +92,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct TabBarStory; - impl TabBarStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for TabBarStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, TabBar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/terminal.rs b/crates/ui2/src/components/terminal.rs index b7c8c5d75d..a751d47dfc 100644 --- a/crates/ui2/src/components/terminal.rs +++ b/crates/ui2/src/components/terminal.rs @@ -83,15 +83,15 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; - - #[derive(Component)] + use crate::Story; + use gpui2::{Div, Render}; pub struct TerminalStory; - impl TerminalStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for TerminalStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, Terminal>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/theme_selector.rs b/crates/ui2/src/components/theme_selector.rs index b5fcd17d2f..5c67f1cd3e 100644 --- a/crates/ui2/src/components/theme_selector.rs +++ b/crates/ui2/src/components/theme_selector.rs @@ -39,15 +39,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; + use crate::Story; use super::*; - #[derive(Component)] pub struct ThemeSelectorStory; - impl ThemeSelectorStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ThemeSelectorStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, ThemeSelector>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/title_bar.rs b/crates/ui2/src/components/title_bar.rs index 29622d1395..4b3b125dea 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::{AppContext, Context, ModelContext, View}; +use gpui2::{Div, Render, View, VisualContext}; use crate::prelude::*; use crate::settings::user_settings; @@ -28,7 +28,7 @@ pub struct TitleBar { } impl TitleBar { - pub fn new(cx: &mut ModelContext) -> Self { + pub fn new(cx: &mut ViewContext) -> Self { let is_active = Arc::new(AtomicBool::new(true)); let active = is_active.clone(); @@ -80,15 +80,15 @@ impl TitleBar { cx.notify(); } - pub fn view(cx: &mut AppContext, livestream: Option) -> View { - { - let state = cx.build_model(|cx| Self::new(cx).set_livestream(livestream)); - let render = Self::render; - View::for_handle(state, render) - } + pub fn view(cx: &mut WindowContext, livestream: Option) -> View { + cx.build_view(|cx| Self::new(cx).set_livestream(livestream)) } +} - fn render(&mut self, cx: &mut ViewContext) -> impl Component { +impl Render for TitleBar { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Div { let theme = theme(cx); let settings = user_settings(cx); @@ -187,26 +187,25 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; pub struct TitleBarStory { title_bar: View, } impl TitleBarStory { - pub fn view(cx: &mut AppContext) -> View { - { - let state = cx.build_model(|cx| Self { - title_bar: TitleBar::view(cx, None), - }); - let render = Self::render; - View::for_handle(state, render) - } + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| Self { + title_bar: TitleBar::view(cx, None), + }) } + } - fn render(&mut self, cx: &mut ViewContext) -> impl Component { + impl Render for TitleBarStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Div { Story::container(cx) .child(Story::title_for::<_, TitleBar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/toast.rs b/crates/ui2/src/components/toast.rs index dca6f7c28a..814e91c498 100644 --- a/crates/ui2/src/components/toast.rs +++ b/crates/ui2/src/components/toast.rs @@ -72,17 +72,20 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; + use crate::{Label, Story}; use super::*; - #[derive(Component)] pub struct ToastStory; - impl ToastStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ToastStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) - .child(Story::title_for::<_, Toast>(cx)) + .child(Story::title_for::<_, Toast>(cx)) .child(Story::label(cx, "Default")) .child(Toast::new(ToastOrigin::Bottom).child(Label::new("label"))) } diff --git a/crates/ui2/src/components/toolbar.rs b/crates/ui2/src/components/toolbar.rs index a833090c1c..4b35e2d9d2 100644 --- a/crates/ui2/src/components/toolbar.rs +++ b/crates/ui2/src/components/toolbar.rs @@ -75,19 +75,22 @@ mod stories { use std::path::PathBuf; use std::str::FromStr; + use gpui2::{Div, Render}; + use crate::{Breadcrumb, HighlightedText, Icon, IconButton, Story, Symbol}; use super::*; - #[derive(Component)] pub struct ToolbarStory; - impl ToolbarStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ToolbarStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let theme = theme(cx); Story::container(cx) - .child(Story::title_for::<_, Toolbar>(cx)) + .child(Story::title_for::<_, Toolbar>(cx)) .child(Story::label(cx, "Default")) .child( Toolbar::new() diff --git a/crates/ui2/src/components/traffic_lights.rs b/crates/ui2/src/components/traffic_lights.rs index 320e7e68fd..8ee19d26f5 100644 --- a/crates/ui2/src/components/traffic_lights.rs +++ b/crates/ui2/src/components/traffic_lights.rs @@ -77,15 +77,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; + use crate::Story; use super::*; - #[derive(Component)] pub struct TrafficLightsStory; - impl TrafficLightsStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for TrafficLightsStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, TrafficLights>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/workspace.rs b/crates/ui2/src/components/workspace.rs index f2314fb377..78ab6232a8 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, AppContext, Context, Size, View}; +use gpui2::{px, relative, rems, Div, Render, Size, View, VisualContext}; use crate::{prelude::*, NotificationsPanel}; use crate::{ @@ -44,7 +44,7 @@ pub struct Workspace { } impl Workspace { - pub fn new(cx: &mut AppContext) -> Self { + pub fn new(cx: &mut ViewContext) -> Self { Self { title_bar: TitleBar::view(cx, None), editor_1: EditorPane::view(cx), @@ -170,15 +170,15 @@ impl Workspace { cx.notify(); } - pub fn view(cx: &mut AppContext) -> View { - { - let state = cx.build_model(|cx| Self::new(cx)); - let render = Self::render; - View::for_handle(state, render) - } + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| Self::new(cx)) } +} - pub fn render(&mut self, cx: &mut ViewContext) -> impl Component { +impl Render for Workspace { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Div { let theme = theme(cx); // HACK: This should happen inside of `debug_toggle_user_settings`, but @@ -355,9 +355,8 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use gpui2::VisualContext; - use super::*; + use gpui2::VisualContext; pub struct WorkspaceStory { workspace: View, @@ -365,12 +364,17 @@ mod stories { impl WorkspaceStory { pub fn view(cx: &mut WindowContext) -> View { - cx.build_view( - |cx| Self { - workspace: Workspace::view(cx), - }, - |view, cx| view.workspace.clone(), - ) + cx.build_view(|cx| Self { + workspace: Workspace::view(cx), + }) + } + } + + impl Render for WorkspaceStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + div().child(self.workspace.clone()) } } } diff --git a/crates/ui2/src/elements/avatar.rs b/crates/ui2/src/elements/avatar.rs index 87133209a2..f008eeb479 100644 --- a/crates/ui2/src/elements/avatar.rs +++ b/crates/ui2/src/elements/avatar.rs @@ -43,15 +43,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct AvatarStory; - impl AvatarStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for AvatarStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, Avatar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/button.rs b/crates/ui2/src/elements/button.rs index 15d65dc5d2..d27a0537d8 100644 --- a/crates/ui2/src/elements/button.rs +++ b/crates/ui2/src/elements/button.rs @@ -219,22 +219,21 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use gpui2::rems; + use super::*; + use crate::{h_stack, v_stack, LabelColor, Story}; + use gpui2::{rems, Div, Render}; use strum::IntoEnumIterator; - use crate::{h_stack, v_stack, LabelColor, Story}; - - use super::*; - - #[derive(Component)] pub struct ButtonStory; - impl ButtonStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ButtonStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let states = InteractionState::iter(); Story::container(cx) - .child(Story::title_for::<_, Button>(cx)) + .child(Story::title_for::<_, Button>(cx)) .child( div() .flex() diff --git a/crates/ui2/src/elements/details.rs b/crates/ui2/src/elements/details.rs index f89cfb53db..eca7798c82 100644 --- a/crates/ui2/src/elements/details.rs +++ b/crates/ui2/src/elements/details.rs @@ -46,17 +46,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::{Button, Story}; - use super::*; + use crate::{Button, Story}; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct DetailsStory; - impl DetailsStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for DetailsStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) - .child(Story::title_for::<_, Details>(cx)) + .child(Story::title_for::<_, Details>(cx)) .child(Story::label(cx, "Default")) .child(Details::new("The quick brown fox jumps over the lazy dog")) .child(Story::label(cx, "With meta")) diff --git a/crates/ui2/src/elements/icon.rs b/crates/ui2/src/elements/icon.rs index ef36442296..4e4ec2bce7 100644 --- a/crates/ui2/src/elements/icon.rs +++ b/crates/ui2/src/elements/icon.rs @@ -36,7 +36,7 @@ impl IconColor { IconColor::Error => gpui2::red(), IconColor::Warning => gpui2::red(), IconColor::Success => gpui2::red(), - IconColor::Info => gpui2::red() + IconColor::Info => gpui2::red(), } } } @@ -191,17 +191,19 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; use strum::IntoEnumIterator; use crate::Story; use super::*; - #[derive(Component)] pub struct IconStory; - impl IconStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for IconStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let icons = Icon::iter(); Story::container(cx) diff --git a/crates/ui2/src/elements/input.rs b/crates/ui2/src/elements/input.rs index 79a09e0ba2..e9e92dd0a6 100644 --- a/crates/ui2/src/elements/input.rs +++ b/crates/ui2/src/elements/input.rs @@ -112,15 +112,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct InputStory; - impl InputStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for InputStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, Input>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/label.rs b/crates/ui2/src/elements/label.rs index 6c97819eeb..4d336345fb 100644 --- a/crates/ui2/src/elements/label.rs +++ b/crates/ui2/src/elements/label.rs @@ -197,15 +197,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct LabelStory; - impl LabelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for LabelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, Label>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/static_data.rs b/crates/ui2/src/static_data.rs index 72407b6678..68f1e36b2c 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::{AppContext, WindowContext}; +use gpui2::ViewContext; use rand::Rng; use theme2::Theme; @@ -628,7 +628,7 @@ pub fn example_editor_actions() -> Vec { ] } -pub fn empty_editor_example(cx: &mut WindowContext) -> EditorPane { +pub fn empty_editor_example(cx: &mut ViewContext) -> EditorPane { EditorPane::new( cx, static_tabs_example(), @@ -642,7 +642,7 @@ pub fn empty_buffer_example() -> Buffer { Buffer::new("empty-buffer").set_rows(Some(BufferRows::default())) } -pub fn hello_world_rust_editor_example(cx: &mut WindowContext) -> EditorPane { +pub fn hello_world_rust_editor_example(cx: &mut ViewContext) -> EditorPane { let theme = theme(cx); EditorPane::new( @@ -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 AppContext) -> EditorPane { +pub fn hello_world_rust_editor_with_status_example(cx: &mut ViewContext) -> EditorPane { let theme = theme(cx); EditorPane::new(