diff --git a/crates/copilot2/src/sign_in.rs b/crates/copilot2/src/sign_in.rs index ab326a88195e610ae264b82f00a227325a5a8ad7..57f248aa52486d8c04672eeef8d33e5acda2a52c 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 a6efbe52eb3223af3e1444a744574bdce856eea3..15d29a7c42ce404277e156490fe0b2d6dd31cecc 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; + + fn when(mut self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self + where + Self: Sized, + { + if condition { + self = then(self); + } + self + } } -impl IntoAnyElement for AnyElement { - fn into_any(self) -> AnyElement { +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 71196eadcae2b7e49ed195eae298287d4e1693ce..6fe10d94a31324984df8431c13a0747d704110b4 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 adce6aea6b6cd4eb0aaeef019faea1f351c0952b..747e573ea566ec882aa965c3efa0cc01cf6fbf70 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 7e9017264f1c1e21d572cbd20e55d13e1dd4c4e6..7db4c5cf6db86d96bf154c9a4f243c630b0a3fe5 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 7b0052826cd4e5086fbfea95fb5646d4bb9d8656..3aff568c4c2f71ed4002006b3a7c9ae306db3b99 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 3345b4c6c6e64813a5dfb344798d5dc50424f7d0..c283998ca26c575d0bd8373eb7fe6c2a33dd914e 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 fd603eda460765f12800374433f41b2289ef5bb5..9ec6c38dfe967e03423b6071b32f8737d310d44a 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 ed633e8966bfa8a54ae2ac97d1be539e4c07debe..a27faed07de617a613f4d4469afdde76e9210542 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 0000000000000000000000000000000000000000..d1919c8bc4f475b596bff5119ce132f99ea37f95 --- /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 3f6b053aa06ef488dc0a72cea4392307d23bb25b..0000000000000000000000000000000000000000 --- 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 59fd046c839a1a4be8e480942fca04695d125c7c..2e0c0547f79e29f1e3bcc5bfcc43cfed516f7df9 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 c39ccaa3d9a36504e84c41c950ad296e08a9c04d..a3dca51adc44050e31473a3e3e526d7f2a4b381e 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 e7c4e752f6f85d85b070ec96b9415bdcd22fa2fe..ec89238ac45ef68a51e9e3a69545248112a8f697 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 c5df3bd3d318ecceb3634cbe19a287060422b224..a1e3c6700e4ac47646467d0e9ffb8cf495a5a90f 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 9dd74b6884d5d901ad3009d6694caaf6239c8217..7fa078c4e3fc70b7a3900c958f5df02c854d4390 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 8cd3f9e3294d6c555af686e3038936af56eb8d3d..5f60ad14eaddf51323f92ecb9c509951df7b8eb3 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 c6d71f079dac09704104167fa4c728525372be76..29ff5eaa9801e98f776f17550b851bba4a4b518b 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 31f299de910c90d7671b9267748796880e6901c8..defd05f500904e1b6a4974300c49df8f35745fe9 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 e67ceb1751cb54e41b153f12c6a83b4db27285ea..3cba3b7248a668f5499a7da35b739a3c84711422 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 2e0e07e16c8ac7ecab113986d1139adb7339db2e..b4ccb89b5c994665a71c35f4a41924288849b97f 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 1edbd58c8775e0eb59ca9d4678400a688895b58a..b5e74a481004b9373710ecafd90b51df7654760d 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 7afccd6d9d5ae23a9c88e09dc3d703380c3d2748..e4494f461487365187aed31839a455bf38d655a5 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 6414e0e5ffbf00e3cd93cfc5d823e5e86ada2eda..6d2cbd8e14e402bfd2bc0d1480d4408c4767765d 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 45194e843c7a856ce45cf752bb60e09b0d911888..065ee9a052bdbe219cff6b7a4b4fff68f2c81aea 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 73813ed61356926fec81d9c509b01a2de0d67cd5..3e0323d9422af69bf5b204ca935d9756a160f5e9 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 b0f20cfa0d8928d949918a4bfa661534cfcfdbab..3c48ef20d085b7d5b0f9b44cb80aebf684d05e5f 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 7489b3e47d8edfa2c5d1e0f2544a33aa71804e4c..9c9638d0579f89e430353816a96c1cab1b2f1613 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 9a96d8001053e1c6ea81d347d5a781aca23a39a8..898489f1edb27551880201d1704068a4b0e4913a 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 b74165720d15f0b78486d2d40fb9e6df07bcd6fd..2891ce6bd837fd2d63d2194387c449dcc321fa23 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 2fb40adac6446c1cc47d1682466110c6705db228..2b0eefa4eaa347bf8c6b5b3d05f985921a824298 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 224db69754441e0fd0e1f362c5ba534d423c8403..db42b28281171e243a1d8b7c47e6d67ac1c4dd02 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 99282fa06dd45ef1834942bfae1c56946a2fcb4c..0bf413e2172654db6b2828cc383928ec05fa6499 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