diff --git a/crates/copilot2/src/sign_in.rs b/crates/copilot2/src/sign_in.rs index ab326a8819..57f248aa52 100644 --- a/crates/copilot2/src/sign_in.rs +++ b/crates/copilot2/src/sign_in.rs @@ -106,7 +106,7 @@ // data: &PromptUserDeviceFlow, // style: &theme::Copilot, // cx: &mut ViewContext, -// ) -> impl Element { +// ) -> impl IntoAnyElement { // let copied = cx // .read_from_clipboard() // .map(|item| item.text() == &data.user_code) diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index a6efbe52eb..15d29a7c42 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -3,36 +3,37 @@ use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; use std::{any::Any, mem}; -pub trait Element: IntoAnyElement { - type ViewState: 'static; +pub trait Element { type ElementState: 'static; fn id(&self) -> Option; + /// Called to initialize this element for the current frame. If this + /// element had state in a previous frame, it will be passed in for the 3rd argument. fn initialize( &mut self, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self::ElementState; // where - // Self::ViewState: Any + Send + Sync; + // V: Any + Send + Sync; fn layout( &mut self, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> LayoutId; // where - // Self::ViewState: Any + Send + Sync; + // V: Any + Send + Sync; fn paint( &mut self, bounds: Bounds, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ); // where @@ -42,26 +43,23 @@ pub trait Element: IntoAnyElement { #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)] pub struct GlobalElementId(SmallVec<[ElementId; 32]>); -pub trait ParentElement: Element { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; +pub trait ParentElement { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; - fn child(mut self, child: impl IntoAnyElement) -> Self + fn child(mut self, child: impl Component) -> Self where Self: Sized, { - self.children_mut().push(child.into_any()); + self.children_mut().push(child.render()); self } - fn children( - mut self, - iter: impl IntoIterator>, - ) -> Self + fn children(mut self, iter: impl IntoIterator>) -> Self where Self: Sized, { self.children_mut() - .extend(iter.into_iter().map(|item| item.into_any())); + .extend(iter.into_iter().map(|item| item.render())); self } } @@ -72,7 +70,7 @@ trait ElementObject { fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext); } -struct RenderedElement { +struct RenderedElement> { element: E, phase: ElementRenderPhase, } @@ -94,7 +92,7 @@ enum ElementRenderPhase { /// Internal struct that wraps an element to store Layout and ElementState after the element is rendered. /// It's allocated as a trait object to erase the element type and wrapped in AnyElement for /// improved usability. -impl RenderedElement { +impl> RenderedElement { fn new(element: E) -> Self { RenderedElement { element, @@ -103,13 +101,13 @@ impl RenderedElement { } } -impl ElementObject for RenderedElement +impl ElementObject for RenderedElement where - E: Element, + E: Element, // E::ViewState: Any + Send + Sync, E::ElementState: Any + Send + Sync, { - fn initialize(&mut self, view_state: &mut E::ViewState, cx: &mut ViewContext) { + fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext) { let frame_state = if let Some(id) = self.element.id() { cx.with_element_state(id, |element_state, cx| { let element_state = self.element.initialize(view_state, element_state, cx); @@ -124,7 +122,7 @@ where self.phase = ElementRenderPhase::Initialized { frame_state }; } - fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext) -> LayoutId { + fn layout(&mut self, state: &mut V, cx: &mut ViewContext) -> LayoutId { let layout_id; let mut frame_state; match mem::take(&mut self.phase) { @@ -154,7 +152,7 @@ where layout_id } - fn paint(&mut self, view_state: &mut E::ViewState, cx: &mut ViewContext) { + fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext) { self.phase = match mem::take(&mut self.phase) { ElementRenderPhase::LayoutRequested { layout_id, @@ -182,11 +180,15 @@ where pub struct AnyElement(Box + Send + Sync>); +unsafe impl Send for AnyElement {} +unsafe impl Sync for AnyElement {} + impl AnyElement { pub fn new(element: E) -> Self where + V: 'static, E: 'static + Send + Sync, - E: Element, + E: Element, E::ElementState: Any + Send + Sync, { AnyElement(Box::new(RenderedElement::new(element))) @@ -205,12 +207,88 @@ impl AnyElement { } } -pub trait IntoAnyElement { - fn into_any(self) -> AnyElement; -} +pub trait Component { + fn render(self) -> AnyElement; -impl IntoAnyElement for AnyElement { - fn into_any(self) -> AnyElement { + fn when(mut self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self + where + Self: Sized, + { + if condition { + self = then(self); + } self } } + +impl Component for AnyElement { + fn render(self) -> AnyElement { + self + } +} + +impl Element for Option +where + V: 'static, + E: 'static + Component + Send + Sync, + F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + Sync + 'static, +{ + type ElementState = AnyElement; + + fn id(&self) -> Option { + None + } + + fn initialize( + &mut self, + view_state: &mut V, + _rendered_element: Option, + cx: &mut ViewContext, + ) -> Self::ElementState { + let render = self.take().unwrap(); + let mut rendered_element = (render)(view_state, cx).render(); + rendered_element.initialize(view_state, cx); + rendered_element + } + + fn layout( + &mut self, + view_state: &mut V, + rendered_element: &mut Self::ElementState, + cx: &mut ViewContext, + ) -> LayoutId { + rendered_element.layout(view_state, cx) + } + + fn paint( + &mut self, + _bounds: Bounds, + view_state: &mut V, + rendered_element: &mut Self::ElementState, + cx: &mut ViewContext, + ) { + rendered_element.paint(view_state, cx) + } +} + +impl Component for Option +where + V: 'static, + E: 'static + Component + Send + Sync, + F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + Sync + 'static, +{ + fn render(self) -> AnyElement { + AnyElement::new(self) + } +} + +impl Component for F +where + V: 'static, + E: 'static + Component + Send + Sync, + F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + Sync + 'static, +{ + fn render(self) -> AnyElement { + AnyElement::new(Some(self)) + } +} diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index 71196eadca..6fe10d94a3 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -1,7 +1,7 @@ use crate::{ - point, AnyElement, BorrowWindow, Bounds, Element, ElementFocus, ElementId, ElementInteraction, - FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable, GlobalElementId, - GroupBounds, InteractiveElementState, IntoAnyElement, LayoutId, Overflow, ParentElement, + point, AnyElement, BorrowWindow, Bounds, Component, Element, ElementFocus, ElementId, + ElementInteraction, FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable, + GlobalElementId, GroupBounds, InteractiveElementState, LayoutId, Overflow, ParentElement, Pixels, Point, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction, StatelessInteractive, Style, StyleRefinement, Styled, ViewContext, }; @@ -160,7 +160,7 @@ impl Div, FocusDisabled> { } } -impl Focusable for Div> +impl Focusable for Div> where V: 'static, I: ElementInteraction, @@ -189,12 +189,11 @@ pub struct DivState { child_layout_ids: SmallVec<[LayoutId; 4]>, } -impl Element for Div +impl Element for Div where I: ElementInteraction, F: ElementFocus, { - type ViewState = V; type ElementState = DivState; fn id(&self) -> Option { @@ -205,9 +204,9 @@ where fn initialize( &mut self, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self::ElementState { let mut element_state = element_state.unwrap_or_default(); self.focus @@ -224,9 +223,9 @@ where fn layout( &mut self, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> LayoutId { let style = self.compute_style(Bounds::default(), element_state, cx); style.apply_text_style(cx, |cx| { @@ -245,9 +244,9 @@ where fn paint( &mut self, bounds: Bounds, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) { self.with_element_id(cx, |this, _global_id, cx| { if let Some(group) = this.group.clone() { @@ -304,23 +303,23 @@ where } } -impl IntoAnyElement for Div +impl Component for Div where // V: Any + Send + Sync, I: ElementInteraction, F: ElementFocus, { - fn into_any(self) -> AnyElement { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl ParentElement for Div +impl ParentElement for Div where I: ElementInteraction, F: ElementFocus, { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { &mut self.children } } @@ -335,7 +334,7 @@ where } } -impl StatelessInteractive for Div +impl StatelessInteractive for Div where I: ElementInteraction, F: ElementFocus, @@ -345,11 +344,11 @@ where } } -impl StatefulInteractive for Div, F> +impl StatefulInteractive for Div, F> where F: ElementFocus, { - fn stateful_interaction(&mut self) -> &mut StatefulInteraction { + fn stateful_interaction(&mut self) -> &mut StatefulInteraction { &mut self.interaction } } diff --git a/crates/gpui2/src/elements/img.rs b/crates/gpui2/src/elements/img.rs index adce6aea6b..747e573ea5 100644 --- a/crates/gpui2/src/elements/img.rs +++ b/crates/gpui2/src/elements/img.rs @@ -1,6 +1,6 @@ use crate::{ - div, AnyElement, BorrowWindow, Bounds, Div, DivState, Element, ElementFocus, ElementId, - ElementInteraction, FocusDisabled, FocusEnabled, FocusListeners, Focusable, IntoAnyElement, + div, AnyElement, BorrowWindow, Bounds, Component, Div, DivState, Element, ElementFocus, + ElementId, ElementInteraction, FocusDisabled, FocusEnabled, FocusListeners, Focusable, LayoutId, Pixels, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction, StatelessInteractive, StyleRefinement, Styled, ViewContext, }; @@ -55,22 +55,21 @@ where } } -impl IntoAnyElement for Img +impl Component for Img where I: ElementInteraction, F: ElementFocus, { - fn into_any(self) -> AnyElement { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl Element for Img +impl Element for Img where I: ElementInteraction, F: ElementFocus, { - type ViewState = V; type ElementState = DivState; fn id(&self) -> Option { @@ -90,7 +89,7 @@ where &mut self, view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> LayoutId { self.base.layout(view_state, element_state, cx) } @@ -143,7 +142,7 @@ where } } -impl StatelessInteractive for Img +impl StatelessInteractive for Img where I: ElementInteraction, F: ElementFocus, @@ -153,21 +152,21 @@ where } } -impl StatefulInteractive for Img, F> +impl StatefulInteractive for Img, F> where F: ElementFocus, { - fn stateful_interaction(&mut self) -> &mut StatefulInteraction { + fn stateful_interaction(&mut self) -> &mut StatefulInteraction { self.base.stateful_interaction() } } -impl Focusable for Img> +impl Focusable for Img> where V: 'static, I: ElementInteraction, { - fn focus_listeners(&mut self) -> &mut FocusListeners { + fn focus_listeners(&mut self) -> &mut FocusListeners { self.base.focus_listeners() } diff --git a/crates/gpui2/src/elements/svg.rs b/crates/gpui2/src/elements/svg.rs index 7e9017264f..7db4c5cf6d 100644 --- a/crates/gpui2/src/elements/svg.rs +++ b/crates/gpui2/src/elements/svg.rs @@ -1,6 +1,6 @@ use crate::{ - div, AnyElement, Bounds, Div, DivState, Element, ElementFocus, ElementId, ElementInteraction, - FocusDisabled, FocusEnabled, FocusListeners, Focusable, IntoAnyElement, LayoutId, Pixels, + div, AnyElement, Bounds, Component, Div, DivState, Element, ElementFocus, ElementId, + ElementInteraction, FocusDisabled, FocusEnabled, FocusListeners, Focusable, LayoutId, Pixels, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction, StatelessInteractive, StyleRefinement, Styled, ViewContext, }; @@ -45,22 +45,21 @@ where } } -impl IntoAnyElement for Svg +impl Component for Svg where I: ElementInteraction, F: ElementFocus, { - fn into_any(self) -> AnyElement { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl Element for Svg +impl Element for Svg where I: ElementInteraction, F: ElementFocus, { - type ViewState = V; type ElementState = DivState; fn id(&self) -> Option { @@ -80,7 +79,7 @@ where &mut self, view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> LayoutId { self.base.layout(view_state, element_state, cx) } @@ -88,7 +87,7 @@ where fn paint( &mut self, bounds: Bounds, - view: &mut Self::ViewState, + view: &mut V, element_state: &mut Self::ElementState, cx: &mut ViewContext, ) where @@ -116,7 +115,7 @@ where } } -impl StatelessInteractive for Svg +impl StatelessInteractive for Svg where I: ElementInteraction, F: ElementFocus, @@ -126,21 +125,21 @@ where } } -impl StatefulInteractive for Svg, F> +impl StatefulInteractive for Svg, F> where V: 'static, F: ElementFocus, { - fn stateful_interaction(&mut self) -> &mut StatefulInteraction { + fn stateful_interaction(&mut self) -> &mut StatefulInteraction { self.base.stateful_interaction() } } -impl Focusable for Svg> +impl Focusable for Svg> where I: ElementInteraction, { - fn focus_listeners(&mut self) -> &mut FocusListeners { + fn focus_listeners(&mut self) -> &mut FocusListeners { self.base.focus_listeners() } diff --git a/crates/gpui2/src/elements/text.rs b/crates/gpui2/src/elements/text.rs index 7b0052826c..3aff568c4c 100644 --- a/crates/gpui2/src/elements/text.rs +++ b/crates/gpui2/src/elements/text.rs @@ -1,41 +1,41 @@ use crate::{ - AnyElement, BorrowWindow, Bounds, Element, IntoAnyElement, LayoutId, Line, Pixels, - SharedString, Size, ViewContext, + AnyElement, BorrowWindow, Bounds, Component, Element, LayoutId, Line, Pixels, SharedString, + Size, ViewContext, }; use parking_lot::Mutex; use smallvec::SmallVec; use std::{marker::PhantomData, sync::Arc}; use util::ResultExt; -impl IntoAnyElement for SharedString { - fn into_any(self) -> AnyElement { +impl Component for SharedString { + fn render(self) -> AnyElement { Text { text: self, state_type: PhantomData, } - .into_any() + .render() } } -impl IntoAnyElement for &'static str { - fn into_any(self) -> AnyElement { +impl Component for &'static str { + fn render(self) -> AnyElement { Text { text: self.into(), state_type: PhantomData, } - .into_any() + .render() } } // TODO: Figure out how to pass `String` to `child` without this. // This impl doesn't exist in the `gpui2` crate. -impl IntoAnyElement for String { - fn into_any(self) -> AnyElement { +impl Component for String { + fn render(self) -> AnyElement { Text { text: self.into(), state_type: PhantomData, } - .into_any() + .render() } } @@ -47,14 +47,13 @@ pub struct Text { unsafe impl Send for Text {} unsafe impl Sync for Text {} -impl IntoAnyElement for Text { - fn into_any(self) -> AnyElement { +impl Component for Text { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl Element for Text { - type ViewState = V; +impl Element for Text { type ElementState = Arc>>; fn id(&self) -> Option { diff --git a/crates/gpui2/src/focusable.rs b/crates/gpui2/src/focusable.rs index 3345b4c6c6..c283998ca2 100644 --- a/crates/gpui2/src/focusable.rs +++ b/crates/gpui2/src/focusable.rs @@ -11,8 +11,8 @@ pub type FocusListeners = SmallVec<[FocusListener; 2]>; pub type FocusListener = Arc) + Send + Sync + 'static>; -pub trait Focusable: Element { - fn focus_listeners(&mut self) -> &mut FocusListeners; +pub trait Focusable: Element { + fn focus_listeners(&mut self) -> &mut FocusListeners; fn set_focus_style(&mut self, style: StyleRefinement); fn set_focus_in_style(&mut self, style: StyleRefinement); fn set_in_focus_style(&mut self, style: StyleRefinement); @@ -43,10 +43,7 @@ pub trait Focusable: Element { fn on_focus( mut self, - listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -62,10 +59,7 @@ pub trait Focusable: Element { fn on_blur( mut self, - listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -81,10 +75,7 @@ pub trait Focusable: Element { fn on_focus_in( mut self, - listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -109,10 +100,7 @@ pub trait Focusable: Element { fn on_focus_out( mut self, - listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index fd603eda46..9ec6c38dfe 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -1,7 +1,7 @@ use crate::{ - point, px, view, Action, AnyBox, AnyDrag, AppContext, BorrowWindow, Bounds, DispatchContext, - DispatchPhase, Element, ElementId, FocusHandle, KeyMatch, Keystroke, Modifiers, Overflow, - Pixels, Point, SharedString, Size, Style, StyleRefinement, ViewContext, + point, px, view, Action, AnyBox, AnyDrag, AppContext, BorrowWindow, Bounds, Component, + DispatchContext, DispatchPhase, Element, ElementId, FocusHandle, KeyMatch, Keystroke, + Modifiers, Overflow, Pixels, Point, SharedString, Size, Style, StyleRefinement, ViewContext, }; use collections::HashMap; use derive_more::{Deref, DerefMut}; @@ -19,8 +19,8 @@ use std::{ const DRAG_THRESHOLD: f64 = 2.; -pub trait StatelessInteractive: Element { - fn stateless_interaction(&mut self) -> &mut StatelessInteraction; +pub trait StatelessInteractive: Element { + fn stateless_interaction(&mut self) -> &mut StatelessInteraction; fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self where @@ -48,10 +48,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_down( mut self, button: MouseButton, - handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext) - + Send - + Sync - + 'static, + handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -72,10 +69,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_up( mut self, button: MouseButton, - handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext) - + Send - + Sync - + 'static, + handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -96,10 +90,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_down_out( mut self, button: MouseButton, - handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext) - + Send - + Sync - + 'static, + handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -120,10 +111,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_up_out( mut self, button: MouseButton, - handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext) - + Send - + Sync - + 'static, + handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -143,10 +131,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_move( mut self, - handler: impl Fn(&mut Self::ViewState, &MouseMoveEvent, &mut ViewContext) - + Send - + Sync - + 'static, + handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -163,10 +148,7 @@ pub trait StatelessInteractive: Element { fn on_scroll_wheel( mut self, - handler: impl Fn(&mut Self::ViewState, &ScrollWheelEvent, &mut ViewContext) - + Send - + Sync - + 'static, + handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -194,10 +176,7 @@ pub trait StatelessInteractive: Element { fn on_action( mut self, - listener: impl Fn(&mut Self::ViewState, &A, DispatchPhase, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &A, DispatchPhase, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -215,12 +194,8 @@ pub trait StatelessInteractive: Element { fn on_key_down( mut self, - listener: impl Fn( - &mut Self::ViewState, - &KeyDownEvent, - DispatchPhase, - &mut ViewContext, - ) + Send + listener: impl Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext) + + Send + Sync + 'static, ) -> Self @@ -240,7 +215,7 @@ pub trait StatelessInteractive: Element { fn on_key_up( mut self, - listener: impl Fn(&mut Self::ViewState, &KeyUpEvent, DispatchPhase, &mut ViewContext) + listener: impl Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext) + Send + Sync + 'static, @@ -289,10 +264,7 @@ pub trait StatelessInteractive: Element { fn on_drop( mut self, - listener: impl Fn(&mut Self::ViewState, S, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, S, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -307,8 +279,8 @@ pub trait StatelessInteractive: Element { } } -pub trait StatefulInteractive: StatelessInteractive { - fn stateful_interaction(&mut self) -> &mut StatefulInteraction; +pub trait StatefulInteractive: StatelessInteractive { + fn stateful_interaction(&mut self) -> &mut StatefulInteraction; fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self where @@ -335,10 +307,7 @@ pub trait StatefulInteractive: StatelessInteractive { fn on_click( mut self, - listener: impl Fn(&mut Self::ViewState, &ClickEvent, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &ClickEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -351,20 +320,14 @@ pub trait StatefulInteractive: StatelessInteractive { fn on_drag( mut self, - listener: impl Fn( - &mut Self::ViewState, - &mut ViewContext, - ) -> Drag - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &mut ViewContext) -> Drag + Send + Sync + 'static, ) -> Self where Self: Sized, S: Any + Send + Sync, - R: Fn(&mut Self::ViewState, &mut ViewContext) -> E, + R: Fn(&mut V, &mut ViewContext) -> E, R: 'static + Send + Sync, - E: Element, + E: Component, { debug_assert!( self.stateful_interaction().drag_listener.is_none(), @@ -907,7 +870,8 @@ pub struct ClickEvent { pub struct Drag where R: Fn(&mut V, &mut ViewContext) -> E, - E: Element, + V: 'static, + E: Component, { pub state: S, pub render_drag_handle: R, @@ -917,7 +881,8 @@ where impl Drag where R: Fn(&mut V, &mut ViewContext) -> E, - E: Element, + V: 'static, + E: Component, { pub fn new(state: S, render_drag_handle: R) -> Self { Drag { diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index ed633e8966..a27faed07d 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -1,7 +1,7 @@ use parking_lot::Mutex; use crate::{ - AnyBox, AnyElement, BorrowWindow, Bounds, Element, ElementId, EntityId, Handle, IntoAnyElement, + AnyBox, AnyElement, BorrowWindow, Bounds, Component, Element, ElementId, EntityId, Handle, LayoutId, Pixels, ViewContext, WindowContext, }; use std::{marker::PhantomData, sync::Arc}; @@ -33,16 +33,16 @@ pub fn view( render: impl Fn(&mut V, &mut ViewContext) -> E + Send + Sync + 'static, ) -> View where - E: IntoAnyElement, + E: Component, { View { state, - render: Arc::new(move |state, cx| render(state, cx).into_any()), + render: Arc::new(move |state, cx| render(state, cx).render()), } } -impl IntoAnyElement for View { - fn into_any(self) -> AnyElement { +impl Component for View { + fn render(self) -> AnyElement { AnyElement::new(EraseViewState { view: self, parent_view_state_type: PhantomData, @@ -50,8 +50,7 @@ impl IntoAnyElement for V } } -impl Element for View { - type ViewState = (); +impl Element<()> for View { type ElementState = AnyElement; fn id(&self) -> Option { @@ -99,14 +98,13 @@ struct EraseViewState { unsafe impl Send for EraseViewState {} unsafe impl Sync for EraseViewState {} -impl IntoAnyElement for EraseViewState { - fn into_any(self) -> AnyElement { +impl Component for EraseViewState { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl Element for EraseViewState { - type ViewState = ParentV; +impl Element for EraseViewState { type ElementState = AnyBox; fn id(&self) -> Option { @@ -115,18 +113,18 @@ impl Element for EraseViewState { fn initialize( &mut self, - _: &mut Self::ViewState, + _: &mut ParentV, _: Option, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self::ElementState { ViewObject::initialize(&mut self.view, cx) } fn layout( &mut self, - _: &mut Self::ViewState, + _: &mut ParentV, element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> LayoutId { ViewObject::layout(&mut self.view, element, cx) } @@ -134,9 +132,9 @@ impl Element for EraseViewState { fn paint( &mut self, bounds: Bounds, - _: &mut Self::ViewState, + _: &mut ParentV, element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) { ViewObject::paint(&mut self.view, bounds, element, cx) } @@ -187,8 +185,8 @@ pub struct AnyView { view: Arc>, } -impl IntoAnyElement for AnyView { - fn into_any(self) -> AnyElement { +impl Component for AnyView { + fn render(self) -> AnyElement { AnyElement::new(EraseAnyViewState { view: self, parent_view_state_type: PhantomData, @@ -196,8 +194,7 @@ impl IntoAnyElement for AnyView { } } -impl Element for AnyView { - type ViewState = (); +impl Element<()> for AnyView { type ElementState = AnyBox; fn id(&self) -> Option { @@ -206,18 +203,18 @@ impl Element for AnyView { fn initialize( &mut self, - _: &mut Self::ViewState, + _: &mut (), _: Option, - cx: &mut ViewContext, + cx: &mut ViewContext<()>, ) -> Self::ElementState { self.view.lock().initialize(cx) } fn layout( &mut self, - _: &mut Self::ViewState, + _: &mut (), element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext<()>, ) -> LayoutId { self.view.lock().layout(element, cx) } @@ -227,7 +224,7 @@ impl Element for AnyView { bounds: Bounds, _: &mut (), element: &mut AnyBox, - cx: &mut ViewContext, + cx: &mut ViewContext<()>, ) { self.view.lock().paint(bounds, element, cx) } @@ -241,14 +238,13 @@ struct EraseAnyViewState { unsafe impl Send for EraseAnyViewState {} unsafe impl Sync for EraseAnyViewState {} -impl IntoAnyElement for EraseAnyViewState { - fn into_any(self) -> AnyElement { +impl Component for EraseAnyViewState { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl Element for EraseAnyViewState { - type ViewState = ParentV; +impl Element for EraseAnyViewState { type ElementState = AnyBox; fn id(&self) -> Option { @@ -257,18 +253,18 @@ impl Element for EraseAnyViewState { fn initialize( &mut self, - _: &mut Self::ViewState, + _: &mut ParentV, _: Option, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self::ElementState { self.view.view.lock().initialize(cx) } fn layout( &mut self, - _: &mut Self::ViewState, + _: &mut ParentV, element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> LayoutId { self.view.view.lock().layout(element, cx) } @@ -276,9 +272,9 @@ impl Element for EraseAnyViewState { fn paint( &mut self, bounds: Bounds, - _: &mut Self::ViewState, + _: &mut ParentV, element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) { self.view.view.lock().paint(bounds, element, cx) } diff --git a/crates/gpui2_macros/src/derive_component.rs b/crates/gpui2_macros/src/derive_component.rs new file mode 100644 index 0000000000..d1919c8bc4 --- /dev/null +++ b/crates/gpui2_macros/src/derive_component.rs @@ -0,0 +1,66 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, parse_quote, DeriveInput}; + +pub fn derive_component(input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + let name = &ast.ident; + + let mut trait_generics = ast.generics.clone(); + let view_type = if let Some(view_type) = specified_view_type(&ast) { + quote! { #view_type } + } else { + if let Some(first_type_param) = ast.generics.params.iter().find_map(|param| { + if let syn::GenericParam::Type(type_param) = param { + Some(type_param.ident.clone()) + } else { + None + } + }) { + quote! { #first_type_param } + } else { + trait_generics.params.push(parse_quote! { V: 'static }); + quote! { V } + } + }; + + let (impl_generics, _, where_clause) = trait_generics.split_for_impl(); + let (_, ty_generics, _) = ast.generics.split_for_impl(); + + let expanded = quote! { + impl #impl_generics gpui2::Component<#view_type> for #name #ty_generics #where_clause { + fn render(self) -> gpui2::AnyElement<#view_type> { + (move |view_state: &mut #view_type, cx: &mut gpui2::ViewContext<'_, '_, #view_type>| self.render(view_state, cx)) + .render() + } + } + }; + + TokenStream::from(expanded) +} + +fn specified_view_type(ast: &DeriveInput) -> Option { + let component_attr = ast + .attrs + .iter() + .find(|attr| attr.path.is_ident("component"))?; + + if let Ok(syn::Meta::List(meta_list)) = component_attr.parse_meta() { + meta_list.nested.iter().find_map(|nested| { + if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = nested { + if nv.path.is_ident("view_type") { + if let syn::Lit::Str(lit_str) = &nv.lit { + return Some( + lit_str + .parse::() + .expect("Failed to parse view_type"), + ); + } + } + } + None + }) + } else { + None + } +} diff --git a/crates/gpui2_macros/src/derive_element.rs b/crates/gpui2_macros/src/derive_element.rs deleted file mode 100644 index 3f6b053aa0..0000000000 --- a/crates/gpui2_macros/src/derive_element.rs +++ /dev/null @@ -1,95 +0,0 @@ -use proc_macro::TokenStream; -use quote::quote; -use syn::{parse_macro_input, DeriveInput, GenericParam}; - -pub fn derive_element(input: TokenStream) -> TokenStream { - let ast = parse_macro_input!(input as DeriveInput); - let type_name = ast.ident; - - let mut state_type = quote! { () }; - - for param in &ast.generics.params { - if let GenericParam::Type(type_param) = param { - let type_ident = &type_param.ident; - state_type = quote! {#type_ident}; - break; - } - } - - let attrs = &ast.attrs; - for attr in attrs { - if attr.path.is_ident("element") { - match attr.parse_meta() { - Ok(syn::Meta::List(i)) => { - for nested_meta in i.nested { - if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = nested_meta { - if nv.path.is_ident("view_state") { - if let syn::Lit::Str(lit_str) = nv.lit { - state_type = lit_str.value().parse().unwrap(); - } - } - } - } - } - _ => (), - } - } - } - - let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); - - let gen = quote! { - impl #impl_generics gpui2::IntoAnyElement<#state_type> for #type_name #ty_generics - #where_clause - { - fn into_any(self) -> gpui2::AnyElement<#state_type> { - gpui2::AnyElement::new(self) - } - } - - impl #impl_generics gpui2::Element for #type_name #ty_generics - #where_clause - { - type ViewState = #state_type; - type ElementState = gpui2::AnyElement<#state_type>; - - fn id(&self) -> Option { - None - } - - fn initialize( - &mut self, - view_state: &mut Self::ViewState, - _: Option, - cx: &mut gpui2::ViewContext - ) -> Self::ElementState { - use gpui2::IntoAnyElement; - - let mut element = self.render(view_state, cx).into_any(); - element.initialize(view_state, cx); - element - } - - fn layout( - &mut self, - view_state: &mut Self::ViewState, - rendered_element: &mut Self::ElementState, - cx: &mut gpui2::ViewContext, - ) -> gpui2::LayoutId { - rendered_element.layout(view_state, cx) - } - - fn paint( - &mut self, - bounds: gpui2::Bounds, - view_state: &mut Self::ViewState, - rendered_element: &mut Self::ElementState, - cx: &mut gpui2::ViewContext, - ) { - rendered_element.paint(view_state, cx) - } - } - }; - - gen.into() -} diff --git a/crates/gpui2_macros/src/gpui2_macros.rs b/crates/gpui2_macros/src/gpui2_macros.rs index 59fd046c83..2e0c0547f7 100644 --- a/crates/gpui2_macros/src/gpui2_macros.rs +++ b/crates/gpui2_macros/src/gpui2_macros.rs @@ -1,6 +1,6 @@ use proc_macro::TokenStream; -mod derive_element; +mod derive_component; mod style_helpers; mod test; @@ -9,9 +9,9 @@ pub fn style_helpers(args: TokenStream) -> TokenStream { style_helpers::style_helpers(args) } -#[proc_macro_derive(Element, attributes(element))] -pub fn derive_element(input: TokenStream) -> TokenStream { - derive_element::derive_element(input) +#[proc_macro_derive(Component, attributes(component))] +pub fn derive_component(input: TokenStream) -> TokenStream { + derive_component::derive_component(input) } #[proc_macro_attribute] diff --git a/crates/storybook2/src/components.rs b/crates/storybook2/src/components.rs index c39ccaa3d9..a3dca51adc 100644 --- a/crates/storybook2/src/components.rs +++ b/crates/storybook2/src/components.rs @@ -14,7 +14,7 @@ impl Default for ButtonHandlers { } } -#[derive(Element)] +#[derive(Component)] pub struct Button { handlers: ButtonHandlers, label: Option>, diff --git a/crates/storybook2/src/stories/kitchen_sink.rs b/crates/storybook2/src/stories/kitchen_sink.rs index e7c4e752f6..ec89238ac4 100644 --- a/crates/storybook2/src/stories/kitchen_sink.rs +++ b/crates/storybook2/src/stories/kitchen_sink.rs @@ -16,7 +16,7 @@ impl KitchenSinkStory { view(cx.entity(|cx| Self::new()), Self::render) } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl Component { 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 c5df3bd3d3..a1e3c6700e 100644 --- a/crates/storybook2/src/stories/scroll.rs +++ b/crates/storybook2/src/stories/scroll.rs @@ -1,8 +1,7 @@ use crate::themes::rose_pine; use gpui2::{ - div, px, view, Context, Element, ParentElement, SharedString, Styled, View, WindowContext, + div, px, view, Component, Context, ParentElement, SharedString, Styled, View, WindowContext, }; -use ui::ElementExt; pub struct ScrollStory { text: View<()>, @@ -16,7 +15,7 @@ impl ScrollStory { } } -fn checkerboard(depth: usize) -> impl Element +fn checkerboard(depth: usize) -> impl Component where S: 'static + Send + Sync, { diff --git a/crates/storybook2/src/stories/z_index.rs b/crates/storybook2/src/stories/z_index.rs index 9dd74b6884..7fa078c4e3 100644 --- a/crates/storybook2/src/stories/z_index.rs +++ b/crates/storybook2/src/stories/z_index.rs @@ -1,4 +1,3 @@ -use std::marker::PhantomData; use gpui2::{px, rgb, Div, Hsla}; use ui::prelude::*; @@ -7,19 +6,15 @@ 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(Element)] -pub struct ZIndexStory { - state_type: PhantomData, -} +#[derive(Component)] +pub struct ZIndexStory; -impl ZIndexStory { +impl ZIndexStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title(cx, "z-index")) .child( @@ -86,23 +81,19 @@ trait Styles: Styled + Sized { } } -impl Styles for Div {} +impl Styles for Div {} -#[derive(Element)] -struct ZIndexExample { - state_type: PhantomData, +#[derive(Component)] +struct ZIndexExample { z_index: u32, } -impl ZIndexExample { +impl ZIndexExample { pub fn new(z_index: u32) -> Self { - Self { - state_type: PhantomData, - z_index, - } + Self { z_index } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { div() .relative() .size_full() diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook2/src/story_selector.rs index 8cd3f9e329..5f60ad14ea 100644 --- a/crates/storybook2/src/story_selector.rs +++ b/crates/storybook2/src/story_selector.rs @@ -28,29 +28,29 @@ impl ElementStory { pub fn story(&self, cx: &mut WindowContext) -> AnyView { match self { Self::Avatar => { - view(cx.entity(|cx| ()), |_, _| ui::AvatarStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::AvatarStory::new().render()).into_any() } Self::Button => { - view(cx.entity(|cx| ()), |_, _| ui::ButtonStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::ButtonStory::new().render()).into_any() } Self::Details => view(cx.entity(|cx| ()), |_, _| { - ui::DetailsStory::new().into_any() + ui::DetailsStory::new().render() }) .into_any(), Self::Focus => FocusStory::view(cx).into_any(), Self::Icon => { - view(cx.entity(|cx| ()), |_, _| ui::IconStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::IconStory::new().render()).into_any() } Self::Input => { - view(cx.entity(|cx| ()), |_, _| ui::InputStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::InputStory::new().render()).into_any() } Self::Label => { - view(cx.entity(|cx| ()), |_, _| ui::LabelStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::LabelStory::new().render()).into_any() } Self::Scroll => ScrollStory::view(cx).into_any(), Self::Text => TextStory::view(cx).into_any(), Self::ZIndex => { - view(cx.entity(|cx| ()), |_, _| ZIndexStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ZIndexStory::new().render()).into_any() } } } @@ -91,93 +91,93 @@ impl ComponentStory { pub fn story(&self, cx: &mut WindowContext) -> AnyView { match self { Self::AssistantPanel => view(cx.entity(|cx| ()), |_, _| { - ui::AssistantPanelStory::new().into_any() + ui::AssistantPanelStory::new().render() }) .into_any(), Self::Buffer => { - view(cx.entity(|cx| ()), |_, _| ui::BufferStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::BufferStory::new().render()).into_any() } Self::Breadcrumb => view(cx.entity(|cx| ()), |_, _| { - ui::BreadcrumbStory::new().into_any() + ui::BreadcrumbStory::new().render() }) .into_any(), Self::ChatPanel => view(cx.entity(|cx| ()), |_, _| { - ui::ChatPanelStory::new().into_any() + ui::ChatPanelStory::new().render() }) .into_any(), Self::CollabPanel => view(cx.entity(|cx| ()), |_, _| { - ui::CollabPanelStory::new().into_any() + ui::CollabPanelStory::new().render() }) .into_any(), Self::CommandPalette => view(cx.entity(|cx| ()), |_, _| { - ui::CommandPaletteStory::new().into_any() + ui::CommandPaletteStory::new().render() }) .into_any(), Self::ContextMenu => view(cx.entity(|cx| ()), |_, _| { - ui::ContextMenuStory::new().into_any() + ui::ContextMenuStory::new().render() }) .into_any(), Self::Facepile => view(cx.entity(|cx| ()), |_, _| { - ui::FacepileStory::new().into_any() + ui::FacepileStory::new().render() }) .into_any(), Self::Keybinding => view(cx.entity(|cx| ()), |_, _| { - ui::KeybindingStory::new().into_any() + ui::KeybindingStory::new().render() }) .into_any(), Self::LanguageSelector => view(cx.entity(|cx| ()), |_, _| { - ui::LanguageSelectorStory::new().into_any() + ui::LanguageSelectorStory::new().render() }) .into_any(), Self::MultiBuffer => view(cx.entity(|cx| ()), |_, _| { - ui::MultiBufferStory::new().into_any() + ui::MultiBufferStory::new().render() }) .into_any(), Self::NotificationsPanel => view(cx.entity(|cx| ()), |_, _| { - ui::NotificationsPanelStory::new().into_any() + ui::NotificationsPanelStory::new().render() }) .into_any(), Self::Palette => view(cx.entity(|cx| ()), |_, _| { - ui::PaletteStory::new().into_any() + ui::PaletteStory::new().render() }) .into_any(), Self::Panel => { - view(cx.entity(|cx| ()), |_, _| ui::PanelStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::PanelStory::new().render()).into_any() } Self::ProjectPanel => view(cx.entity(|cx| ()), |_, _| { - ui::ProjectPanelStory::new().into_any() + ui::ProjectPanelStory::new().render() }) .into_any(), Self::RecentProjects => view(cx.entity(|cx| ()), |_, _| { - ui::RecentProjectsStory::new().into_any() + ui::RecentProjectsStory::new().render() }) .into_any(), - Self::Tab => view(cx.entity(|cx| ()), |_, _| ui::TabStory::new().into_any()).into_any(), + Self::Tab => view(cx.entity(|cx| ()), |_, _| ui::TabStory::new().render()).into_any(), Self::TabBar => { - view(cx.entity(|cx| ()), |_, _| ui::TabBarStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::TabBarStory::new().render()).into_any() } Self::Terminal => view(cx.entity(|cx| ()), |_, _| { - ui::TerminalStory::new().into_any() + ui::TerminalStory::new().render() }) .into_any(), Self::ThemeSelector => view(cx.entity(|cx| ()), |_, _| { - ui::ThemeSelectorStory::new().into_any() + ui::ThemeSelectorStory::new().render() }) .into_any(), Self::TitleBar => ui::TitleBarStory::view(cx).into_any(), Self::Toast => { - view(cx.entity(|cx| ()), |_, _| ui::ToastStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::ToastStory::new().render()).into_any() } Self::Toolbar => view(cx.entity(|cx| ()), |_, _| { - ui::ToolbarStory::new().into_any() + ui::ToolbarStory::new().render() }) .into_any(), Self::TrafficLights => view(cx.entity(|cx| ()), |_, _| { - ui::TrafficLightsStory::new().into_any() + ui::TrafficLightsStory::new().render() }) .into_any(), Self::Copilot => view(cx.entity(|cx| ()), |_, _| { - ui::CopilotModalStory::new().into_any() + ui::CopilotModalStory::new().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 c6d71f079d..29ff5eaa98 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, Element, ViewContext, WindowBounds, + div, px, size, view, AnyView, AppContext, Bounds, Context, ViewContext, WindowBounds, WindowOptions, }; use log::LevelFilter; @@ -107,7 +107,7 @@ impl StoryWrapper { Self { story, theme } } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl Component { themed(self.theme.clone(), cx, |cx| { div() .flex() diff --git a/crates/ui2/src/components/assistant_panel.rs b/crates/ui2/src/components/assistant_panel.rs index 31f299de91..defd05f500 100644 --- a/crates/ui2/src/components/assistant_panel.rs +++ b/crates/ui2/src/components/assistant_panel.rs @@ -1,22 +1,18 @@ -use std::marker::PhantomData; - use gpui2::{rems, AbsoluteLength}; use crate::prelude::*; use crate::{Icon, IconButton, Label, Panel, PanelSide}; -#[derive(Element)] -pub struct AssistantPanel { +#[derive(Component)] +pub struct AssistantPanel { id: ElementId, - state_type: PhantomData, current_side: PanelSide, } -impl AssistantPanel { +impl AssistantPanel { pub fn new(id: impl Into) -> Self { Self { id: id.into(), - state_type: PhantomData, current_side: PanelSide::default(), } } @@ -26,7 +22,7 @@ impl AssistantPanel { self } - fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, view: &mut V, cx: &mut ViewContext) -> impl Component { Panel::new(self.id.clone(), cx) .children(vec![div() .flex() @@ -69,7 +65,7 @@ impl AssistantPanel { .overflow_y_scroll() .child(Label::new("Is this thing on?")), ) - .into_any()]) + .render()]) .side(self.current_side) .width(AbsoluteLength::Rems(rems(32.))) } @@ -84,25 +80,17 @@ mod stories { use super::*; - #[derive(Element)] - pub struct AssistantPanelStory { - state_type: PhantomData, - } + #[derive(Component)] + pub struct AssistantPanelStory {} - impl AssistantPanelStory { + impl AssistantPanelStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self {} } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, AssistantPanel>(cx)) + .child(Story::title_for::<_, AssistantPanel>(cx)) .child(Story::label(cx, "Default")) .child(AssistantPanel::new("assistant-panel")) } diff --git a/crates/ui2/src/components/breadcrumb.rs b/crates/ui2/src/components/breadcrumb.rs index e67ceb1751..3cba3b7248 100644 --- a/crates/ui2/src/components/breadcrumb.rs +++ b/crates/ui2/src/components/breadcrumb.rs @@ -1,41 +1,33 @@ -use std::marker::PhantomData; use std::path::PathBuf; use gpui2::Div; - use crate::prelude::*; use crate::{h_stack, HighlightedText}; #[derive(Clone)] pub struct Symbol(pub Vec); -#[derive(Element)] -pub struct Breadcrumb { - state_type: PhantomData, +#[derive(Component)] +pub struct Breadcrumb { path: PathBuf, symbols: Vec, } -impl Breadcrumb { +impl Breadcrumb { pub fn new(path: PathBuf, symbols: Vec) -> Self { Self { - state_type: PhantomData, path, symbols, } } - fn render_separator(&self, cx: &WindowContext) -> Div { + fn render_separator(&self, cx: &WindowContext) -> Div { let theme = theme(cx); div().child(" › ").text_color(theme.text_muted) } - fn render( - &mut self, - view_state: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(self, view_state: &mut V, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let symbols_len = self.symbols.len(); @@ -90,27 +82,19 @@ mod stories { use super::*; - #[derive(Element)] - pub struct BreadcrumbStory { - state_type: PhantomData, - } + #[derive(Component)] + pub struct BreadcrumbStory; - impl BreadcrumbStory { + impl BreadcrumbStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render( - &mut self, - view_state: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(self, view_state: &mut V, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); Story::container(cx) - .child(Story::title_for::<_, Breadcrumb>(cx)) + .child(Story::title_for::<_, Breadcrumb>(cx)) .child(Story::label(cx, "Default")) .child(Breadcrumb::new( PathBuf::from_str("crates/ui/src/components/toolbar.rs").unwrap(), diff --git a/crates/ui2/src/components/buffer.rs b/crates/ui2/src/components/buffer.rs index 2e0e07e16c..b4ccb89b5c 100644 --- a/crates/ui2/src/components/buffer.rs +++ b/crates/ui2/src/components/buffer.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use gpui2::{Hsla, WindowContext}; use crate::prelude::*; @@ -109,10 +107,9 @@ impl BufferRow { } } -#[derive(Element, Clone)] -pub struct Buffer { +#[derive(Component, Clone)] +pub struct Buffer { id: ElementId, - state_type: PhantomData, rows: Option, readonly: bool, language: Option, @@ -120,11 +117,10 @@ pub struct Buffer { path: Option, } -impl Buffer { +impl Buffer { pub fn new(id: impl Into) -> Self { Self { id: id.into(), - state_type: PhantomData, rows: Some(BufferRows::default()), readonly: false, language: None, @@ -158,7 +154,7 @@ impl Buffer { self } - fn render_row(row: BufferRow, cx: &WindowContext) -> impl Element { + fn render_row(row: BufferRow, cx: &WindowContext) -> impl Component { let theme = theme(cx); let line_background = if row.current { @@ -208,7 +204,7 @@ impl Buffer { })) } - fn render_rows(&self, cx: &WindowContext) -> Vec> { + fn render_rows(&self, cx: &WindowContext) -> Vec> { match &self.rows { Some(rows) => rows .rows @@ -219,7 +215,7 @@ impl Buffer { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let rows = self.render_rows(cx); @@ -246,27 +242,19 @@ mod stories { use super::*; - #[derive(Element)] - pub struct BufferStory { - state_type: PhantomData, - } + #[derive(Component)] + pub struct BufferStory; - impl BufferStory { + impl BufferStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); Story::container(cx) - .child(Story::title_for::<_, Buffer>(cx)) + .child(Story::title_for::<_, Buffer>(cx)) .child(Story::label(cx, "Default")) .child(div().w(rems(64.)).h_96().child(empty_buffer_example())) .child(Story::label(cx, "Hello World (Rust)")) diff --git a/crates/ui2/src/components/buffer_search.rs b/crates/ui2/src/components/buffer_search.rs index 1edbd58c87..b5e74a4810 100644 --- a/crates/ui2/src/components/buffer_search.rs +++ b/crates/ui2/src/components/buffer_search.rs @@ -25,7 +25,7 @@ impl BufferSearch { view(cx.entity(|cx| Self::new()), Self::render) } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl Component { 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 7afccd6d9d..e4494f4614 100644 --- a/crates/ui2/src/components/chat_panel.rs +++ b/crates/ui2/src/components/chat_panel.rs @@ -1,17 +1,15 @@ -use std::marker::PhantomData; - use chrono::NaiveDateTime; use crate::prelude::*; use crate::{Icon, IconButton, Input, Label, LabelColor}; -#[derive(Element)] -pub struct ChatPanel { +#[derive(Component)] +pub struct ChatPanel { element_id: ElementId, - messages: Vec>, + messages: Vec, } -impl ChatPanel { +impl ChatPanel { pub fn new(element_id: impl Into) -> Self { Self { element_id: element_id.into(), @@ -19,12 +17,12 @@ impl ChatPanel { } } - pub fn messages(mut self, messages: Vec>) -> Self { + pub fn messages(mut self, messages: Vec) -> Self { self.messages = messages; self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div() .id(self.element_id.clone()) .flex() @@ -70,25 +68,23 @@ impl ChatPanel { } } -#[derive(Element)] -pub struct ChatMessage { - state_type: PhantomData, +#[derive(Component)] +pub struct ChatMessage { author: String, text: String, sent_at: NaiveDateTime, } -impl ChatMessage { +impl ChatMessage { pub fn new(author: String, text: String, sent_at: NaiveDateTime) -> Self { Self { - state_type: PhantomData, author, text, sent_at, } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div() .flex() .flex_col() @@ -117,25 +113,17 @@ mod stories { use super::*; - #[derive(Element)] - pub struct ChatPanelStory { - state_type: PhantomData, - } + #[derive(Component)] + pub struct ChatPanelStory; - impl ChatPanelStory { + impl ChatPanelStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, ChatPanel>(cx)) + .child(Story::title_for::<_, ChatPanel>(cx)) .child(Story::label(cx, "Default")) .child( Panel::new("chat-panel-1-outer", cx) diff --git a/crates/ui2/src/components/collab_panel.rs b/crates/ui2/src/components/collab_panel.rs index 6414e0e5ff..6d2cbd8e14 100644 --- a/crates/ui2/src/components/collab_panel.rs +++ b/crates/ui2/src/components/collab_panel.rs @@ -3,23 +3,18 @@ use crate::{ static_collab_panel_channels, static_collab_panel_current_call, v_stack, Icon, List, ListHeader, ToggleState, }; -use std::marker::PhantomData; -#[derive(Element)] -pub struct CollabPanel { +#[derive(Component)] +pub struct CollabPanel { id: ElementId, - state_type: PhantomData, } -impl CollabPanel { +impl CollabPanel { pub fn new(id: impl Into) -> Self { - Self { - id: id.into(), - state_type: PhantomData, - } + Self { id: id.into() } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); v_stack() @@ -98,25 +93,17 @@ mod stories { use super::*; - #[derive(Element)] - pub struct CollabPanelStory { - state_type: PhantomData, - } + #[derive(Component)] + pub struct CollabPanelStory; - impl CollabPanelStory { + impl CollabPanelStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, CollabPanel>(cx)) + .child(Story::title_for::<_, CollabPanel>(cx)) .child(Story::label(cx, "Default")) .child(CollabPanel::new("collab-panel")) } diff --git a/crates/ui2/src/components/command_palette.rs b/crates/ui2/src/components/command_palette.rs index 45194e843c..065ee9a052 100644 --- a/crates/ui2/src/components/command_palette.rs +++ b/crates/ui2/src/components/command_palette.rs @@ -1,23 +1,17 @@ -use std::marker::PhantomData; - use crate::prelude::*; use crate::{example_editor_actions, OrderMethod, Palette}; -#[derive(Element)] -pub struct CommandPalette { +#[derive(Component)] +pub struct CommandPalette { id: ElementId, - state_type: PhantomData, } -impl CommandPalette { +impl CommandPalette { pub fn new(id: impl Into) -> Self { - Self { - id: id.into(), - state_type: PhantomData, - } + Self { id: id.into() } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div().id(self.id.clone()).child( Palette::new("palette") .items(example_editor_actions()) @@ -37,25 +31,17 @@ mod stories { use super::*; - #[derive(Element)] - pub struct CommandPaletteStory { - state_type: PhantomData, - } + #[derive(Component)] + pub struct CommandPaletteStory; - impl CommandPaletteStory { + impl CommandPaletteStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, CommandPalette>(cx)) + .child(Story::title_for::<_, CommandPalette>(cx)) .child(Story::label(cx, "Default")) .child(CommandPalette::new("command-palette")) } diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index 73813ed613..3e0323d942 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -1,14 +1,14 @@ use crate::{prelude::*, ListItemVariant}; use crate::{v_stack, Label, List, ListEntry, ListItem, ListSeparator, ListSubHeader}; -pub enum ContextMenuItem { +pub enum ContextMenuItem { Header(SharedString), - Entry(Label), + Entry(Label), Separator, } -impl ContextMenuItem { - fn to_list_item(self) -> ListItem { +impl ContextMenuItem { + fn to_list_item(self) -> ListItem { match self { ContextMenuItem::Header(label) => ListSubHeader::new(label).into(), ContextMenuItem::Entry(label) => { @@ -26,23 +26,23 @@ impl ContextMenuItem { Self::Separator } - pub fn entry(label: Label) -> Self { + pub fn entry(label: Label) -> Self { Self::Entry(label) } } -#[derive(Element)] -pub struct ContextMenu { - items: Vec>, +#[derive(Component)] +pub struct ContextMenu { + items: Vec, } -impl ContextMenu { - pub fn new(items: impl IntoIterator>) -> Self { +impl ContextMenu { + pub fn new(items: impl IntoIterator) -> Self { Self { items: items.into_iter().collect(), } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); v_stack() @@ -67,31 +67,21 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use std::marker::PhantomData; - use crate::story::Story; use super::*; - #[derive(Element)] - pub struct ContextMenuStory { - state_type: PhantomData, - } + #[derive(Component)] + pub struct ContextMenuStory; - impl ContextMenuStory { + impl ContextMenuStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, ContextMenu>(cx)) + .child(Story::title_for::<_, ContextMenu>(cx)) .child(Story::label(cx, "Default")) .child(ContextMenu::new([ ContextMenuItem::header("Section header"), diff --git a/crates/ui2/src/components/copilot.rs b/crates/ui2/src/components/copilot.rs index b0f20cfa0d..3c48ef20d0 100644 --- a/crates/ui2/src/components/copilot.rs +++ b/crates/ui2/src/components/copilot.rs @@ -1,22 +1,16 @@ -use std::marker::PhantomData; - use crate::{prelude::*, Button, Label, LabelColor, Modal}; -#[derive(Element)] -pub struct CopilotModal { +#[derive(Component)] +pub struct CopilotModal { id: ElementId, - state_type: PhantomData, } -impl CopilotModal { +impl CopilotModal { pub fn new(id: impl Into) -> Self { - Self { - id: id.into(), - state_type: PhantomData, - } + Self { id: id.into() } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div().id(self.id.clone()).child( Modal::new("some-id") .title("Connect Copilot to Zed") @@ -35,25 +29,17 @@ mod stories { use super::*; - #[derive(Element)] - pub struct CopilotModalStory { - state_type: PhantomData, - } + #[derive(Component)] + pub struct CopilotModalStory; - impl CopilotModalStory { + impl CopilotModalStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, CopilotModal>(cx)) + .child(Story::title_for::<_, CopilotModal>(cx)) .child(Story::label(cx, "Default")) .child(CopilotModal::new("copilot-modal")) } diff --git a/crates/ui2/src/components/editor_pane.rs b/crates/ui2/src/components/editor_pane.rs index 7489b3e47d..9c9638d057 100644 --- a/crates/ui2/src/components/editor_pane.rs +++ b/crates/ui2/src/components/editor_pane.rs @@ -10,10 +10,10 @@ use crate::{ #[derive(Clone)] pub struct EditorPane { - tabs: Vec>, + tabs: Vec, path: PathBuf, symbols: Vec, - buffer: Buffer, + buffer: Buffer, buffer_search: View, is_buffer_search_open: bool, } @@ -21,10 +21,10 @@ pub struct EditorPane { impl EditorPane { pub fn new( cx: &mut WindowContext, - tabs: Vec>, + tabs: Vec, path: PathBuf, symbols: Vec, - buffer: Buffer, + buffer: Buffer, ) -> Self { Self { tabs, @@ -49,7 +49,7 @@ impl EditorPane { ) } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl Component { v_stack() .w_full() .h_full() diff --git a/crates/ui2/src/components/facepile.rs b/crates/ui2/src/components/facepile.rs index 9a96d80010..898489f1ed 100644 --- a/crates/ui2/src/components/facepile.rs +++ b/crates/ui2/src/components/facepile.rs @@ -1,23 +1,19 @@ -use std::marker::PhantomData; - use crate::prelude::*; use crate::{Avatar, Player}; -#[derive(Element)] -pub struct Facepile { - state_type: PhantomData, +#[derive(Component)] +pub struct Facepile { players: Vec, } -impl Facepile { +impl Facepile { pub fn new>(players: P) -> Self { Self { - state_type: PhantomData, players: players.collect(), } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let player_count = self.players.len(); let player_list = self.players.iter().enumerate().map(|(ix, player)| { let isnt_last = ix < player_count - 1; @@ -39,27 +35,19 @@ mod stories { use super::*; - #[derive(Element)] - pub struct FacepileStory { - state_type: PhantomData, - } + #[derive(Component)] + pub struct FacepileStory; - impl FacepileStory { + impl FacepileStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let players = static_players(); Story::container(cx) - .child(Story::title_for::<_, Facepile>(cx)) + .child(Story::title_for::<_, Facepile>(cx)) .child(Story::label(cx, "Default")) .child( div() diff --git a/crates/ui2/src/components/icon_button.rs b/crates/ui2/src/components/icon_button.rs index b74165720d..2891ce6bd8 100644 --- a/crates/ui2/src/components/icon_button.rs +++ b/crates/ui2/src/components/icon_button.rs @@ -1,4 +1,3 @@ -use std::marker::PhantomData; use std::sync::Arc; use gpui2::MouseButton; @@ -6,19 +5,18 @@ use gpui2::MouseButton; use crate::{h_stack, prelude::*}; use crate::{ClickHandler, Icon, IconColor, IconElement}; -struct IconButtonHandlers { +struct IconButtonHandlers { click: Option>, } -impl Default for IconButtonHandlers { +impl Default for IconButtonHandlers { fn default() -> Self { Self { click: None } } } -#[derive(Element)] -pub struct IconButton { - state_type: PhantomData, +#[derive(Component)] +pub struct IconButton { id: ElementId, icon: Icon, color: IconColor, @@ -27,10 +25,9 @@ pub struct IconButton { handlers: IconButtonHandlers, } -impl IconButton { +impl IconButton { pub fn new(id: impl Into, icon: Icon) -> Self { Self { - state_type: PhantomData, id: id.into(), icon, color: IconColor::default(), @@ -60,15 +57,12 @@ impl IconButton { self } - pub fn on_click( - mut self, - handler: impl Fn(&mut S, &mut ViewContext) + 'static + Send + Sync, - ) -> Self { + pub fn on_click(mut self, handler: impl 'static + Fn(&mut S, &mut ViewContext) + Send + Sync) -> Self { self.handlers.click = Some(Arc::new(handler)); self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let icon_color = match (self.state, self.color) { diff --git a/crates/ui2/src/components/keybinding.rs b/crates/ui2/src/components/keybinding.rs index 2fb40adac6..2b0eefa4ea 100644 --- a/crates/ui2/src/components/keybinding.rs +++ b/crates/ui2/src/components/keybinding.rs @@ -1,14 +1,11 @@ use std::collections::HashSet; -use std::marker::PhantomData; use strum::{EnumIter, IntoEnumIterator}; use crate::prelude::*; -#[derive(Element)] -pub struct Keybinding { - state_type: PhantomData, - +#[derive(Component)] +pub struct Keybinding { /// A keybinding consists of a key and a set of modifier keys. /// More then one keybinding produces a chord. /// @@ -16,10 +13,9 @@ pub struct Keybinding { keybinding: Vec<(String, ModifierKeys)>, } -impl Keybinding { +impl Keybinding { pub fn new(key: String, modifiers: ModifierKeys) -> Self { Self { - state_type: PhantomData, keybinding: vec![(key, modifiers)], } } @@ -29,12 +25,11 @@ impl Keybinding { second_note: (String, ModifierKeys), ) -> Self { Self { - state_type: PhantomData, keybinding: vec![first_note, second_note], } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div() .flex() .gap_2() @@ -54,21 +49,17 @@ impl Keybinding { } } -#[derive(Element)] -pub struct Key { - state_type: PhantomData, +#[derive(Component)] +pub struct Key { key: SharedString, } -impl Key { +impl Key { pub fn new(key: impl Into) -> Self { - Self { - state_type: PhantomData, - key: key.into(), - } + Self { key: key.into() } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); div() @@ -173,27 +164,19 @@ mod stories { use super::*; - #[derive(Element)] - pub struct KeybindingStory { - state_type: PhantomData, - } + #[derive(Component)] + pub struct KeybindingStory; - impl KeybindingStory { + impl KeybindingStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { let all_modifier_permutations = ModifierKey::iter().permutations(2); Story::container(cx) - .child(Story::title_for::<_, Keybinding>(cx)) + .child(Story::title_for::<_, Keybinding>(cx)) .child(Story::label(cx, "Single Key")) .child(Keybinding::new("Z".to_string(), ModifierKeys::new())) .child(Story::label(cx, "Single Key with Modifier")) diff --git a/crates/ui2/src/components/language_selector.rs b/crates/ui2/src/components/language_selector.rs index 224db69754..db42b28281 100644 --- a/crates/ui2/src/components/language_selector.rs +++ b/crates/ui2/src/components/language_selector.rs @@ -1,23 +1,17 @@ -use std::marker::PhantomData; - use crate::prelude::*; use crate::{OrderMethod, Palette, PaletteItem}; -#[derive(Element)] -pub struct LanguageSelector { +#[derive(Component)] +pub struct LanguageSelector { id: ElementId, - state_type: PhantomData, } -impl LanguageSelector { +impl LanguageSelector { pub fn new(id: impl Into) -> Self { - Self { - id: id.into(), - state_type: PhantomData, - } + Self { id: id.into() } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div().id(self.id.clone()).child( Palette::new("palette") .items(vec![ @@ -48,25 +42,17 @@ mod stories { use super::*; - #[derive(Element)] - pub struct LanguageSelectorStory { - state_type: PhantomData, - } + #[derive(Component)] + pub struct LanguageSelectorStory; - impl LanguageSelectorStory { + impl LanguageSelectorStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, LanguageSelector>(cx)) + .child(Story::title_for::<_, LanguageSelector>(cx)) .child(Story::label(cx, "Default")) .child(LanguageSelector::new("language-selector")) } diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index 99282fa06d..0bf413e217 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use gpui2::{div, relative, Div}; use crate::settings::user_settings; @@ -17,9 +15,8 @@ pub enum ListItemVariant { Inset, } -#[derive(Element)] -pub struct ListHeader { - state_type: PhantomData, +#[derive(Component)] +pub struct ListHeader { label: SharedString, left_icon: Option, variant: ListItemVariant, @@ -27,10 +24,9 @@ pub struct ListHeader { toggleable: Toggleable, } -impl ListHeader { +impl ListHeader { pub fn new(label: impl Into) -> Self { Self { - state_type: PhantomData, label: label.into(), left_icon: None, variant: ListItemVariant::default(), @@ -59,7 +55,7 @@ impl ListHeader { self } - fn disclosure_control(&self) -> Div { + fn disclosure_control(&self) -> Div { let is_toggleable = self.toggleable != Toggleable::NotToggleable; let is_toggled = Toggleable::is_toggled(&self.toggleable); @@ -92,7 +88,7 @@ impl ListHeader { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let is_toggleable = self.toggleable != Toggleable::NotToggleable; @@ -134,18 +130,16 @@ impl ListHeader { } } -#[derive(Element)] -pub struct ListSubHeader { - state_type: PhantomData, +#[derive(Component)] +pub struct ListSubHeader { label: SharedString, left_icon: Option, variant: ListItemVariant, } -impl ListSubHeader { +impl ListSubHeader { pub fn new(label: impl Into) -> Self { Self { - state_type: PhantomData, label: label.into(), left_icon: None, variant: ListItemVariant::default(), @@ -157,7 +151,7 @@ impl ListSubHeader { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { h_stack().flex_1().w_full().relative().py_1().child( div() .h_6() @@ -197,40 +191,40 @@ pub enum ListEntrySize { Medium, } -#[derive(Element)] -pub enum ListItem { - Entry(ListEntry), +#[derive(Component)] +pub enum ListItem { + Entry(ListEntry), Details(ListDetailsEntry), - Separator(ListSeparator), - Header(ListSubHeader), + Separator(ListSeparator), + Header(ListSubHeader), } -impl From> for ListItem { - fn from(entry: ListEntry) -> Self { +impl From for ListItem { + fn from(entry: ListEntry) -> Self { Self::Entry(entry) } } -impl From> for ListItem { +impl From> for ListItem { fn from(entry: ListDetailsEntry) -> Self { Self::Details(entry) } } -impl From> for ListItem { - fn from(entry: ListSeparator) -> Self { +impl From for ListItem { + fn from(entry: ListSeparator) -> Self { Self::Separator(entry) } } -impl From> for ListItem { - fn from(entry: ListSubHeader) -> Self { +impl From for ListItem { + fn from(entry: ListSubHeader) -> Self { Self::Header(entry) } } -impl ListItem { - fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { +impl ListItem { + fn render(self, view: &mut S, cx: &mut ViewContext) -> impl Component { match self { ListItem::Entry(entry) => div().child(entry.render(view, cx)), ListItem::Separator(separator) => div().child(separator.render(view, cx)), @@ -239,11 +233,11 @@ impl ListItem { } } - pub fn new(label: Label) -> Self { + pub fn new(label: Label) -> Self { Self::Entry(ListEntry::new(label)) } - pub fn as_entry(&mut self) -> Option<&mut ListEntry> { + pub fn as_entry(&mut self) -> Option<&mut ListEntry> { if let Self::Entry(entry) = self { Some(entry) } else { @@ -252,11 +246,11 @@ impl ListItem { } } -#[derive(Element)] -pub struct ListEntry { +#[derive(Component)] +pub struct ListEntry { disclosure_control_style: DisclosureControlVisibility, indent_level: u32, - label: Option>, + label: Option