diff --git a/crates/gpui2/src/app/test_context.rs b/crates/gpui2/src/app/test_context.rs index 0315e362b0..8687646b4b 100644 --- a/crates/gpui2/src/app/test_context.rs +++ b/crates/gpui2/src/app/test_context.rs @@ -631,7 +631,7 @@ impl AnyWindowHandle { pub struct EmptyView {} impl Render for EmptyView { - type Element = Div; + type Element = Div; fn render(&mut self, _cx: &mut crate::ViewContext) -> Self::Element { div() diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index c773bb6f65..d36f5f1635 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -1,37 +1,34 @@ use crate::{ - AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, ViewContext, + AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, WindowContext, }; use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; use std::{any::Any, fmt::Debug, mem}; -pub trait Element { +pub trait Element { type ElementState: 'static; fn element_id(&self) -> Option; fn layout( &mut self, - view_state: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> (LayoutId, Self::ElementState); fn paint( &mut self, bounds: Bounds, - view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut WindowContext, ); fn draw( self, origin: Point, available_space: Size, - view_state: &mut V, - cx: &mut ViewContext, - f: impl FnOnce(&Self::ElementState, &mut ViewContext) -> R, + cx: &mut WindowContext, + f: impl FnOnce(&Self::ElementState, &mut WindowContext) -> R, ) -> R where Self: Sized, @@ -41,7 +38,7 @@ pub trait Element { element: self, phase: ElementRenderPhase::Start, }; - element.draw(origin, available_space.map(Into::into), view_state, cx); + element.draw(origin, available_space.map(Into::into), cx); if let ElementRenderPhase::Painted { frame_state } = &element.phase { if let Some(frame_state) = frame_state.as_ref() { f(&frame_state, cx) @@ -65,10 +62,10 @@ pub trait Element { #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)] pub struct GlobalElementId(SmallVec<[ElementId; 32]>); -pub trait ParentComponent { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; +pub trait ParentComponent { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; - fn child(mut self, child: impl Component) -> Self + fn child(mut self, child: impl Component) -> Self where Self: Sized, { @@ -76,7 +73,7 @@ pub trait ParentComponent { self } - fn children(mut self, iter: impl IntoIterator>) -> Self + fn children(mut self, iter: impl IntoIterator) -> Self where Self: Sized, { @@ -86,26 +83,24 @@ pub trait ParentComponent { } } -trait ElementObject { +trait ElementObject { fn element_id(&self) -> Option; - fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext) -> LayoutId; - fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext); + fn layout(&mut self, cx: &mut WindowContext) -> LayoutId; + fn paint(&mut self, cx: &mut WindowContext); fn measure( &mut self, available_space: Size, - view_state: &mut V, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> Size; fn draw( &mut self, origin: Point, available_space: Size, - view_state: &mut V, - cx: &mut ViewContext, + cx: &mut WindowContext, ); } -struct RenderedElement> { +struct RenderedElement { element: E, phase: ElementRenderPhase, } @@ -131,7 +126,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, @@ -140,25 +135,25 @@ impl> RenderedElement { } } -impl ElementObject for RenderedElement +impl ElementObject for RenderedElement where - E: Element, + E: Element, E::ElementState: 'static, { fn element_id(&self) -> Option { self.element.element_id() } - fn layout(&mut self, state: &mut V, cx: &mut ViewContext) -> LayoutId { + fn layout(&mut self, cx: &mut WindowContext) -> LayoutId { let (layout_id, frame_state) = match mem::take(&mut self.phase) { ElementRenderPhase::Start => { if let Some(id) = self.element.element_id() { let layout_id = cx.with_element_state(id, |element_state, cx| { - self.element.layout(state, element_state, cx) + self.element.layout(element_state, cx) }); (layout_id, None) } else { - let (layout_id, frame_state) = self.element.layout(state, None, cx); + let (layout_id, frame_state) = self.element.layout(None, cx); (layout_id, Some(frame_state)) } } @@ -176,7 +171,7 @@ where layout_id } - fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext) { + fn paint(&mut self, cx: &mut WindowContext) { self.phase = match mem::take(&mut self.phase) { ElementRenderPhase::LayoutRequested { layout_id, @@ -191,13 +186,12 @@ where if let Some(id) = self.element.element_id() { cx.with_element_state(id, |element_state, cx| { let mut element_state = element_state.unwrap(); - self.element - .paint(bounds, view_state, &mut element_state, cx); + self.element.paint(bounds, &mut element_state, cx); ((), element_state) }); } else { self.element - .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx); + .paint(bounds, frame_state.as_mut().unwrap(), cx); } ElementRenderPhase::Painted { frame_state } } @@ -209,11 +203,10 @@ where fn measure( &mut self, available_space: Size, - view_state: &mut V, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> Size { if matches!(&self.phase, ElementRenderPhase::Start) { - self.layout(view_state, cx); + self.layout(cx); } let layout_id = match &mut self.phase { @@ -251,21 +244,19 @@ where &mut self, origin: Point, available_space: Size, - view_state: &mut V, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { - self.measure(available_space, view_state, cx); - cx.with_absolute_element_offset(origin, |cx| self.paint(view_state, cx)) + self.measure(available_space, cx); + cx.with_absolute_element_offset(origin, |cx| self.paint(cx)) } } -pub struct AnyElement(Box>); +pub struct AnyElement(Box); -impl AnyElement { +impl AnyElement { pub fn new(element: E) -> Self where - V: 'static, - E: 'static + Element, + E: 'static + Element, E::ElementState: Any, { AnyElement(Box::new(RenderedElement::new(element))) @@ -275,22 +266,21 @@ impl AnyElement { self.0.element_id() } - pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext) -> LayoutId { - self.0.layout(view_state, cx) + pub fn layout(&mut self, cx: &mut WindowContext) -> LayoutId { + self.0.layout(cx) } - pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext) { - self.0.paint(view_state, cx) + pub fn paint(&mut self, cx: &mut WindowContext) { + self.0.paint(cx) } /// Initializes this element and performs layout within the given available space to determine its size. pub fn measure( &mut self, available_space: Size, - view_state: &mut V, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> Size { - self.0.measure(available_space, view_state, cx) + self.0.measure(available_space, cx) } /// Initializes this element and performs layout in the available space, then paints it at the given origin. @@ -298,20 +288,19 @@ impl AnyElement { &mut self, origin: Point, available_space: Size, - view_state: &mut V, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { - self.0.draw(origin, available_space, view_state, cx) + self.0.draw(origin, available_space, cx) } } -pub trait Component { - fn render(self) -> AnyElement; +pub trait Component { + fn render(self) -> AnyElement; fn map(self, f: impl FnOnce(Self) -> U) -> U where Self: Sized, - U: Component, + U: Component, { f(self) } @@ -337,19 +326,18 @@ pub trait Component { } } -impl Component for AnyElement { - fn render(self) -> AnyElement { +impl Component for AnyElement { + fn render(self) -> AnyElement { self } } -impl Element for Option +impl Element for Option where - V: 'static, - E: 'static + Component, - F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static, + E: 'static + Component, + F: FnOnce(&mut WindowContext) -> E + 'static, { - type ElementState = AnyElement; + type ElementState = AnyElement; fn element_id(&self) -> Option { None @@ -357,45 +345,41 @@ where fn layout( &mut self, - view_state: &mut V, _: Option, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> (LayoutId, Self::ElementState) { let render = self.take().unwrap(); - let mut rendered_element = (render)(view_state, cx).render(); - let layout_id = rendered_element.layout(view_state, cx); + let mut rendered_element = (render)(cx).render(); + let layout_id = rendered_element.layout(cx); (layout_id, rendered_element) } fn paint( &mut self, _bounds: Bounds, - view_state: &mut V, rendered_element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { - rendered_element.paint(view_state, cx) + rendered_element.paint(cx) } } -impl Component for Option +impl Component for Option where - V: 'static, - E: 'static + Component, - F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static, + E: 'static + Component, + F: FnOnce(&mut WindowContext) -> E + 'static, { - fn render(self) -> AnyElement { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl Component for F +impl Component for F where - V: 'static, - E: 'static + Component, - F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static, + E: 'static + Component, + F: FnOnce(&mut WindowContext) -> E + 'static, { - fn render(self) -> AnyElement { + 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 a37e3dee2a..6587f22552 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -1,9 +1,10 @@ use crate::{ point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, BorrowAppContext, - BorrowWindow, Bounds, ClickEvent, Component, DispatchPhase, Element, ElementId, FocusEvent, - FocusHandle, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, - MouseMoveEvent, MouseUpEvent, ParentComponent, Pixels, Point, Render, ScrollWheelEvent, - SharedString, Size, Style, StyleRefinement, Styled, Task, View, ViewContext, Visibility, + BorrowWindow, Bounds, CallbackHandle, ClickEvent, Component, ConstructorHandle, DispatchPhase, + Element, ElementId, FocusEvent, FocusHandle, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, + MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentComponent, Pixels, Point, + Render, ScrollWheelEvent, SharedString, Size, Style, StyleRefinement, Styled, Task, View, + Visibility, WindowContext, }; use collections::HashMap; use refineable::Refineable; @@ -12,7 +13,6 @@ use std::{ any::{Any, TypeId}, cell::RefCell, fmt::Debug, - marker::PhantomData, mem, rc::Rc, time::Duration, @@ -28,30 +28,24 @@ pub struct GroupStyle { pub style: StyleRefinement, } -pub trait InteractiveComponent: Sized + Element { - fn interactivity(&mut self) -> &mut Interactivity; +pub trait InteractiveComponent: Sized + Element { + fn interactivity(&mut self) -> &mut Interactivity; fn group(mut self, group: impl Into) -> Self { self.interactivity().group = Some(group.into()); self } - fn id(mut self, id: impl Into) -> Stateful { + fn id(mut self, id: impl Into) -> Stateful { self.interactivity().element_id = Some(id.into()); - Stateful { - element: self, - view_type: PhantomData, - } + Stateful { element: self } } - fn track_focus(mut self, focus_handle: &FocusHandle) -> Focusable { + fn track_focus(mut self, focus_handle: &FocusHandle) -> Focusable { self.interactivity().focusable = true; self.interactivity().tracked_focus_handle = Some(focus_handle.clone()); - Focusable { - element: self, - view_type: PhantomData, - } + Focusable { element: self } } fn key_context(mut self, key_context: C) -> Self @@ -85,29 +79,28 @@ pub trait InteractiveComponent: Sized + Element { fn on_mouse_down( mut self, button: MouseButton, - handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext) + 'static, + handler: impl Into>, ) -> Self { + let handler = handler.into(); self.interactivity().mouse_down_listeners.push(Box::new( - move |view, event, bounds, phase, cx| { + move |event, bounds, phase, cx| { if phase == DispatchPhase::Bubble && event.button == button && bounds.contains_point(&event.position) { - handler(view, event, cx) + (handler.callback)(event, cx) } }, )); self } - fn on_any_mouse_down( - mut self, - handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext) + 'static, - ) -> Self { + fn on_any_mouse_down(mut self, handler: impl Into>) -> Self { + let handler = handler.into(); self.interactivity().mouse_down_listeners.push(Box::new( - move |view, event, bounds, phase, cx| { + move |event, bounds, phase, cx| { if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { - handler(view, event, cx) + (handler.callback)(event, cx) } }, )); @@ -117,43 +110,40 @@ pub trait InteractiveComponent: Sized + Element { fn on_mouse_up( mut self, button: MouseButton, - handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext) + 'static, + handler: impl Into>, ) -> Self { - self.interactivity().mouse_up_listeners.push(Box::new( - move |view, event, bounds, phase, cx| { + let handler = handler.into(); + self.interactivity() + .mouse_up_listeners + .push(Box::new(move |event, bounds, phase, cx| { if phase == DispatchPhase::Bubble && event.button == button && bounds.contains_point(&event.position) { - handler(view, event, cx) + (handler.callback)(event, cx) } - }, - )); + })); self } - fn on_any_mouse_up( - mut self, - handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext) + 'static, - ) -> Self { - self.interactivity().mouse_up_listeners.push(Box::new( - move |view, event, bounds, phase, cx| { + fn on_any_mouse_up(mut self, handler: impl Into>) -> Self { + let handler = handler.into(); + self.interactivity() + .mouse_up_listeners + .push(Box::new(move |event, bounds, phase, cx| { if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { - handler(view, event, cx) + (handler.callback)(event, cx) } - }, - )); + })); self } - fn on_mouse_down_out( - mut self, - handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext) + 'static, - ) -> Self { + fn on_mouse_down_out(mut self, handler: impl Into>) -> Self { + let handler = handler.into(); self.interactivity().mouse_down_listeners.push(Box::new( - move |view, event, bounds, phase, cx| { + move |event, bounds, phase, cx| { if phase == DispatchPhase::Capture && !bounds.contains_point(&event.position) { - handler(view, event, cx) + (handler.callback)(event, cx) } }, )); @@ -163,60 +153,55 @@ pub trait InteractiveComponent: Sized + Element { fn on_mouse_up_out( mut self, button: MouseButton, - handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext) + 'static, + handler: impl Into>, ) -> Self { - self.interactivity().mouse_up_listeners.push(Box::new( - move |view, event, bounds, phase, cx| { + let handler = handler.into(); + self.interactivity() + .mouse_up_listeners + .push(Box::new(move |event, bounds, phase, cx| { if phase == DispatchPhase::Capture && event.button == button && !bounds.contains_point(&event.position) { - handler(view, event, cx); + (handler.callback)(event, cx); } - }, - )); + })); self } - fn on_mouse_move( - mut self, - handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext) + 'static, - ) -> Self { + fn on_mouse_move(mut self, handler: impl Into>) -> Self { + let handler = handler.into(); self.interactivity().mouse_move_listeners.push(Box::new( - move |view, event, bounds, phase, cx| { + move |event, bounds, phase, cx| { if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { - handler(view, event, cx); + (handler.callback)(event, cx); } }, )); self } - fn on_scroll_wheel( - mut self, - handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext) + 'static, - ) -> Self { + fn on_scroll_wheel(mut self, handler: impl Into>) -> Self { + let handler = handler.into(); self.interactivity().scroll_wheel_listeners.push(Box::new( - move |view, event, bounds, phase, cx| { + move |event, bounds, phase, cx| { if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { - handler(view, event, cx); + (handler.callback)(event, cx); } }, )); self } - /// Capture the given action, fires during the capture phase - fn capture_action( - mut self, - listener: impl Fn(&mut V, &A, &mut ViewContext) + 'static, - ) -> Self { + /// Capture the given action, before normal action dispatch can fire + fn capture_action(mut self, listener: impl Into>) -> Self { + let listener = listener.into(); self.interactivity().action_listeners.push(( TypeId::of::(), - Box::new(move |view, action, phase, cx| { + Box::new(move |action, phase, cx| { let action = action.downcast_ref().unwrap(); if phase == DispatchPhase::Capture { - listener(view, action, cx) + (listener.callback)(action, cx) } }), )); @@ -224,10 +209,8 @@ pub trait InteractiveComponent: Sized + Element { } /// Add a listener for the given action, fires during the bubble event phase - fn on_action( - mut self, - listener: impl Fn(&mut V, &A, &mut ViewContext) + 'static, - ) -> Self { + fn on_action(mut self, listener: impl Into> + 'static) -> Self { + let handle = listener.into(); // NOTE: this debug assert has the side-effect of working around // a bug where a crate consisting only of action definitions does // not register the actions in debug builds: @@ -244,36 +227,60 @@ pub trait InteractiveComponent: Sized + Element { // ); self.interactivity().action_listeners.push(( TypeId::of::(), - Box::new(move |view, action, phase, cx| { + Box::new(move |action, phase, cx| { let action = action.downcast_ref().unwrap(); if phase == DispatchPhase::Bubble { - listener(view, action, cx) + (handle.callback)(action, cx) } }), )); self } - fn on_key_down( - mut self, - listener: impl Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext) + 'static, - ) -> Self { + fn on_key_down(mut self, listener: impl Into>) -> Self { + let listener = listener.into(); self.interactivity() .key_down_listeners - .push(Box::new(move |view, event, phase, cx| { - listener(view, event, phase, cx) + .push(Box::new(move |event, phase, cx| { + if phase == DispatchPhase::Bubble { + (listener.callback)(event, cx) + } })); self } - fn on_key_up( - mut self, - listener: impl Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext) + 'static, - ) -> Self { + fn capture_key_down(mut self, listener: impl Into>) -> Self { + let listener = listener.into(); + self.interactivity() + .key_down_listeners + .push(Box::new(move |event, phase, cx| { + if phase == DispatchPhase::Capture { + (listener.callback)(event, cx) + } + })); + self + } + + fn on_key_up(mut self, listener: impl Into>) -> Self { + let listener = listener.into(); self.interactivity() .key_up_listeners - .push(Box::new(move |view, event, phase, cx| { - listener(view, event, phase, cx) + .push(Box::new(move |event, phase, cx| { + if phase == DispatchPhase::Bubble { + (listener.callback)(event, cx) + } + })); + self + } + + fn capture_key_up(mut self, listener: impl Into>) -> Self { + let listener = listener.into(); + self.interactivity() + .key_up_listeners + .push(Box::new(move |event, phase, cx| { + if phase == DispatchPhase::Capture { + (listener.callback)(event, cx) + } })); self } @@ -300,27 +307,22 @@ pub trait InteractiveComponent: Sized + Element { self } - fn on_drop( - mut self, - listener: impl Fn(&mut V, View, &mut ViewContext) + 'static, - ) -> Self { + fn on_drop(mut self, listener: impl Into>>) -> Self { + let listener = listener.into(); self.interactivity().drop_listeners.push(( TypeId::of::(), - Box::new(move |view, dragged_view, cx| { - listener(view, dragged_view.downcast().unwrap(), cx); + Box::new(move |dragged_view, cx| { + (listener.callback)(&dragged_view.downcast().unwrap(), cx); }), )); self } } -pub trait StatefulInteractiveComponent>: InteractiveComponent { - fn focusable(mut self) -> Focusable { +pub trait StatefulInteractiveComponent: InteractiveComponent { + fn focusable(mut self) -> Focusable { self.interactivity().focusable = true; - Focusable { - element: self, - view_type: PhantomData, - } + Focusable { element: self } } fn overflow_scroll(mut self) -> Self { @@ -362,70 +364,64 @@ pub trait StatefulInteractiveComponent>: InteractiveCo self } - fn on_click( - mut self, - listener: impl Fn(&mut V, &ClickEvent, &mut ViewContext) + 'static, - ) -> Self + fn on_click(mut self, listener: impl Into>) -> Self where Self: Sized, { + let listener = listener.into(); self.interactivity() .click_listeners - .push(Box::new(move |view, event, cx| listener(view, event, cx))); + .push(Box::new(move |event, cx| (listener.callback)(event, cx))); self } - fn on_drag( - mut self, - listener: impl Fn(&mut V, &mut ViewContext) -> View + 'static, - ) -> Self + fn on_drag(mut self, listener: impl Into>>) -> Self where Self: Sized, W: 'static + Render, { + let listener = listener.into(); debug_assert!( self.interactivity().drag_listener.is_none(), "calling on_drag more than once on the same element is not supported" ); - self.interactivity().drag_listener = - Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag { - view: listener(view_state, cx).into(), - cursor_offset, - })); + self.interactivity().drag_listener = Some(Box::new(move |cursor_offset, cx| AnyDrag { + view: (listener.callback)(cx).into(), + cursor_offset, + })); self } - fn on_hover(mut self, listener: impl 'static + Fn(&mut V, bool, &mut ViewContext)) -> Self + fn on_hover(mut self, listener: impl Into>) -> Self where Self: Sized, { + let listener = listener.into(); debug_assert!( self.interactivity().hover_listener.is_none(), "calling on_hover more than once on the same element is not supported" ); - self.interactivity().hover_listener = Some(Box::new(listener)); + self.interactivity().hover_listener = Some(listener); self } - fn tooltip( - mut self, - build_tooltip: impl Fn(&mut V, &mut ViewContext) -> AnyView + 'static, - ) -> Self + fn tooltip(mut self, build_tooltip: impl Into>) -> Self where Self: Sized, { + let build_tooltip = build_tooltip.into(); debug_assert!( self.interactivity().tooltip_builder.is_none(), "calling tooltip more than once on the same element is not supported" ); self.interactivity().tooltip_builder = - Some(Rc::new(move |view_state, cx| build_tooltip(view_state, cx))); + Some(Rc::new(move |cx| (build_tooltip.callback)(cx))); self } } -pub trait FocusableComponent: InteractiveComponent { +pub trait FocusableComponent: InteractiveComponent { fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self where Self: Sized, @@ -442,49 +438,44 @@ pub trait FocusableComponent: InteractiveComponent { self } - fn on_focus( - mut self, - listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + 'static, - ) -> Self + fn on_focus(mut self, listener: impl Into>) -> Self where Self: Sized, { - self.interactivity().focus_listeners.push(Box::new( - move |view, focus_handle, event, cx| { + let listener = listener.into(); + self.interactivity() + .focus_listeners + .push(Box::new(move |focus_handle, event, cx| { if event.focused.as_ref() == Some(focus_handle) { - listener(view, event, cx) + (listener.callback)(event, cx) } - }, - )); + })); self } - fn on_blur( - mut self, - listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + 'static, - ) -> Self + fn on_blur(mut self, listener: impl Into>) -> Self where Self: Sized, { - self.interactivity().focus_listeners.push(Box::new( - move |view, focus_handle, event, cx| { + let listener = listener.into(); + self.interactivity() + .focus_listeners + .push(Box::new(move |focus_handle, event, cx| { if event.blurred.as_ref() == Some(focus_handle) { - listener(view, event, cx) + (listener.callback)(event, cx) } - }, - )); + })); self } - fn on_focus_in( - mut self, - listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + 'static, - ) -> Self + fn on_focus_in(mut self, listener: impl Into>) -> Self where Self: Sized, { - self.interactivity().focus_listeners.push(Box::new( - move |view, focus_handle, event, cx| { + let listener = listener.into(); + self.interactivity() + .focus_listeners + .push(Box::new(move |focus_handle, event, cx| { let descendant_blurred = event .blurred .as_ref() @@ -495,22 +486,20 @@ pub trait FocusableComponent: InteractiveComponent { .map_or(false, |focused| focus_handle.contains(focused, cx)); if !descendant_blurred && descendant_focused { - listener(view, event, cx) + (listener.callback)(event, cx) } - }, - )); + })); self } - fn on_focus_out( - mut self, - listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + 'static, - ) -> Self + fn on_focus_out(mut self, listener: impl Into>) -> Self where Self: Sized, { - self.interactivity().focus_listeners.push(Box::new( - move |view, focus_handle, event, cx| { + let listener = listener.into(); + self.interactivity() + .focus_listeners + .push(Box::new(move |focus_handle, event, cx| { let descendant_blurred = event .blurred .as_ref() @@ -520,86 +509,73 @@ pub trait FocusableComponent: InteractiveComponent { .as_ref() .map_or(false, |focused| focus_handle.contains(focused, cx)); if descendant_blurred && !descendant_focused { - listener(view, event, cx) + (listener.callback)(event, cx) } - }, - )); + })); self } } -pub type FocusListeners = SmallVec<[FocusListener; 2]>; +pub type FocusListeners = SmallVec<[FocusListener; 2]>; -pub type FocusListener = - Box) + 'static>; +pub type FocusListener = Box; -pub type MouseDownListener = Box< - dyn Fn(&mut V, &MouseDownEvent, &Bounds, DispatchPhase, &mut ViewContext) + 'static, ->; -pub type MouseUpListener = Box< - dyn Fn(&mut V, &MouseUpEvent, &Bounds, DispatchPhase, &mut ViewContext) + 'static, ->; +pub type MouseDownListener = + Box, DispatchPhase, &mut WindowContext) + 'static>; +pub type MouseUpListener = + Box, DispatchPhase, &mut WindowContext) + 'static>; -pub type MouseMoveListener = Box< - dyn Fn(&mut V, &MouseMoveEvent, &Bounds, DispatchPhase, &mut ViewContext) + 'static, ->; +pub type MouseMoveListener = + Box, DispatchPhase, &mut WindowContext) + 'static>; -pub type ScrollWheelListener = Box< - dyn Fn(&mut V, &ScrollWheelEvent, &Bounds, DispatchPhase, &mut ViewContext) - + 'static, ->; +pub type ScrollWheelListener = + Box, DispatchPhase, &mut WindowContext) + 'static>; -pub type ClickListener = Box) + 'static>; +pub type ClickListener = Box; -pub type DragListener = - Box, &mut ViewContext) -> AnyDrag + 'static>; +pub type DragListener = Box, &mut WindowContext) -> AnyDrag + 'static>; -type DropListener = dyn Fn(&mut V, AnyView, &mut ViewContext) + 'static; +type DropListener = dyn Fn(AnyView, &mut WindowContext) + 'static; -pub type HoverListener = Box) + 'static>; +pub type TooltipBuilder = Rc AnyView + 'static>; -pub type TooltipBuilder = Rc) -> AnyView + 'static>; +pub type KeyDownListener = Box; -pub type KeyDownListener = - Box) + 'static>; +pub type KeyUpListener = Box; -pub type KeyUpListener = - Box) + 'static>; +pub type ActionListener = Box; -pub type ActionListener = - Box) + 'static>; - -pub fn div() -> Div { +pub fn div() -> Div { Div { interactivity: Interactivity::default(), children: SmallVec::default(), } } -pub struct Div { - interactivity: Interactivity, - children: SmallVec<[AnyElement; 2]>, +pub struct Div { + interactivity: Interactivity, + children: SmallVec<[AnyElement; 2]>, } -impl Styled for Div { +impl Styled for Div { fn style(&mut self) -> &mut StyleRefinement { &mut self.interactivity.base_style } } -impl InteractiveComponent for Div { - fn interactivity(&mut self) -> &mut Interactivity { +impl InteractiveComponent for Div { + fn interactivity(&mut self) -> &mut Interactivity { &mut self.interactivity } } -impl ParentComponent for Div { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { +impl ParentComponent for Div { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { &mut self.children } } -impl Element for Div { +impl Element for Div { type ElementState = DivState; fn element_id(&self) -> Option { @@ -608,9 +584,8 @@ impl Element for Div { fn layout( &mut self, - view_state: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> (LayoutId, Self::ElementState) { let mut child_layout_ids = SmallVec::new(); let mut interactivity = mem::take(&mut self.interactivity); @@ -622,7 +597,7 @@ impl Element for Div { child_layout_ids = self .children .iter_mut() - .map(|child| child.layout(view_state, cx)) + .map(|child| child.layout(cx)) .collect::>(); cx.request_layout(&style, child_layout_ids.iter().copied()) }) @@ -641,9 +616,8 @@ impl Element for Div { fn paint( &mut self, bounds: Bounds, - view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { let mut child_min = point(Pixels::MAX, Pixels::MAX); let mut child_max = Point::default(); @@ -680,7 +654,7 @@ impl Element for Div { cx.with_content_mask(style.overflow_mask(bounds), |cx| { cx.with_element_offset(scroll_offset, |cx| { for child in &mut self.children { - child.paint(view_state, cx); + child.paint(cx); } }) }) @@ -693,8 +667,8 @@ impl Element for Div { } } -impl Component for Div { - fn render(self) -> AnyElement { +impl Component for Div { + fn render(self) -> AnyElement { AnyElement::new(self) } } @@ -710,12 +684,12 @@ impl DivState { } } -pub struct Interactivity { +pub struct Interactivity { pub element_id: Option, pub key_context: KeyContext, pub focusable: bool, pub tracked_focus_handle: Option, - pub focus_listeners: FocusListeners, + pub focus_listeners: FocusListeners, pub group: Option, pub base_style: StyleRefinement, pub focus_style: StyleRefinement, @@ -726,29 +700,26 @@ pub struct Interactivity { pub group_active_style: Option, pub drag_over_styles: SmallVec<[(TypeId, StyleRefinement); 2]>, pub group_drag_over_styles: SmallVec<[(TypeId, GroupStyle); 2]>, - pub mouse_down_listeners: SmallVec<[MouseDownListener; 2]>, - pub mouse_up_listeners: SmallVec<[MouseUpListener; 2]>, - pub mouse_move_listeners: SmallVec<[MouseMoveListener; 2]>, - pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener; 2]>, - pub key_down_listeners: SmallVec<[KeyDownListener; 2]>, - pub key_up_listeners: SmallVec<[KeyUpListener; 2]>, - pub action_listeners: SmallVec<[(TypeId, ActionListener); 8]>, - pub drop_listeners: SmallVec<[(TypeId, Box>); 2]>, - pub click_listeners: SmallVec<[ClickListener; 2]>, - pub drag_listener: Option>, - pub hover_listener: Option>, - pub tooltip_builder: Option>, + pub mouse_down_listeners: SmallVec<[MouseDownListener; 2]>, + pub mouse_up_listeners: SmallVec<[MouseUpListener; 2]>, + pub mouse_move_listeners: SmallVec<[MouseMoveListener; 2]>, + pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener; 2]>, + pub key_down_listeners: SmallVec<[KeyDownListener; 2]>, + pub key_up_listeners: SmallVec<[KeyUpListener; 2]>, + pub action_listeners: SmallVec<[(TypeId, ActionListener); 8]>, + pub drop_listeners: SmallVec<[(TypeId, Box); 2]>, + pub click_listeners: SmallVec<[ClickListener; 2]>, + pub drag_listener: Option, + pub hover_listener: Option>, + pub tooltip_builder: Option, } -impl Interactivity -where - V: 'static, -{ +impl Interactivity { pub fn layout( &mut self, element_state: Option, - cx: &mut ViewContext, - f: impl FnOnce(Style, &mut ViewContext) -> LayoutId, + cx: &mut WindowContext, + f: impl FnOnce(Style, &mut WindowContext) -> LayoutId, ) -> (LayoutId, InteractiveElementState) { let mut element_state = element_state.unwrap_or_default(); @@ -774,8 +745,8 @@ where bounds: Bounds, content_size: Size, element_state: &mut InteractiveElementState, - cx: &mut ViewContext, - f: impl FnOnce(Style, Point, &mut ViewContext), + cx: &mut WindowContext, + f: impl FnOnce(Style, Point, &mut WindowContext), ) { let style = self.compute_style(Some(bounds), element_state, cx); @@ -787,26 +758,26 @@ where } for listener in self.mouse_down_listeners.drain(..) { - cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| { - listener(state, event, &bounds, phase, cx); + cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| { + listener(event, &bounds, phase, cx); }) } for listener in self.mouse_up_listeners.drain(..) { - cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| { - listener(state, event, &bounds, phase, cx); + cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| { + listener(event, &bounds, phase, cx); }) } for listener in self.mouse_move_listeners.drain(..) { - cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| { - listener(state, event, &bounds, phase, cx); + cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| { + listener(event, &bounds, phase, cx); }) } for listener in self.scroll_wheel_listeners.drain(..) { - cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| { - listener(state, event, &bounds, phase, cx); + cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| { + listener(event, &bounds, phase, cx); }) } @@ -817,7 +788,7 @@ where if let Some(group_bounds) = hover_group_bounds { let hovered = group_bounds.contains_point(&cx.mouse_position()); - cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| { + cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| { if phase == DispatchPhase::Capture { if group_bounds.contains_point(&event.position) != hovered { cx.notify(); @@ -830,7 +801,7 @@ where || (cx.active_drag.is_some() && !self.drag_over_styles.is_empty()) { let hovered = bounds.contains_point(&cx.mouse_position()); - cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| { + cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| { if phase == DispatchPhase::Capture { if bounds.contains_point(&event.position) != hovered { cx.notify(); @@ -841,7 +812,7 @@ where if cx.active_drag.is_some() { let drop_listeners = mem::take(&mut self.drop_listeners); - cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| { + cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| { if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { if let Some(drag_state_type) = cx.active_drag.as_ref().map(|drag| drag.view.entity_type()) @@ -852,7 +823,7 @@ where .active_drag .take() .expect("checked for type drag state type above"); - listener(view, drag.view.clone(), cx); + listener(drag.view.clone(), cx); cx.notify(); cx.stop_propagation(); } @@ -872,7 +843,7 @@ where if let Some(drag_listener) = drag_listener { let active_state = element_state.clicked_state.clone(); - cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| { + cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| { if cx.active_drag.is_some() { if phase == DispatchPhase::Capture { cx.notify(); @@ -883,7 +854,7 @@ where { *active_state.borrow_mut() = ElementClickedState::default(); let cursor_offset = event.position - bounds.origin; - let drag = drag_listener(view_state, cursor_offset, cx); + let drag = drag_listener(cursor_offset, cx); cx.active_drag = Some(drag); cx.notify(); cx.stop_propagation(); @@ -891,21 +862,21 @@ where }); } - cx.on_mouse_event(move |view_state, event: &MouseUpEvent, phase, cx| { + cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| { if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { let mouse_click = ClickEvent { down: mouse_down.clone(), up: event.clone(), }; for listener in &click_listeners { - listener(view_state, &mouse_click, cx); + listener(&mouse_click, cx); } } *pending_mouse_down.borrow_mut() = None; cx.notify(); }); } else { - cx.on_mouse_event(move |_view_state, event: &MouseDownEvent, phase, cx| { + cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| { if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { *pending_mouse_down.borrow_mut() = Some(event.clone()); cx.notify(); @@ -918,7 +889,7 @@ where let was_hovered = element_state.hover_state.clone(); let has_mouse_down = element_state.pending_mouse_down.clone(); - cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| { + cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| { if phase != DispatchPhase::Bubble { return; } @@ -930,7 +901,7 @@ where *was_hovered = is_hovered; drop(was_hovered); - hover_listener(view_state, is_hovered, cx); + (hover_listener.callback)(&is_hovered, cx); } }); } @@ -939,7 +910,7 @@ where let active_tooltip = element_state.active_tooltip.clone(); let pending_mouse_down = element_state.pending_mouse_down.clone(); - cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| { + cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| { if phase != DispatchPhase::Bubble { return; } @@ -956,12 +927,12 @@ where let active_tooltip = active_tooltip.clone(); let tooltip_builder = tooltip_builder.clone(); - move |view, mut cx| async move { + move |mut cx| async move { cx.background_executor().timer(TOOLTIP_DELAY).await; - view.update(&mut cx, move |view_state, cx| { + cx.update(|_, cx| { active_tooltip.borrow_mut().replace(ActiveTooltip { tooltip: Some(AnyTooltip { - view: tooltip_builder(view_state, cx), + view: tooltip_builder(cx), cursor_offset: cx.mouse_position(), }), _task: None, @@ -979,7 +950,7 @@ where }); let active_tooltip = element_state.active_tooltip.clone(); - cx.on_mouse_event(move |_, _: &MouseDownEvent, _, _| { + cx.on_mouse_event(move |_: &MouseDownEvent, _, _| { active_tooltip.borrow_mut().take(); }); @@ -992,7 +963,7 @@ where let active_state = element_state.clicked_state.clone(); if !active_state.borrow().is_clicked() { - cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| { + cx.on_mouse_event(move |_: &MouseUpEvent, phase, cx| { if phase == DispatchPhase::Capture { *active_state.borrow_mut() = ElementClickedState::default(); cx.notify(); @@ -1003,7 +974,7 @@ where .group_active_style .as_ref() .and_then(|group_active| GroupBounds::get(&group_active.group, cx)); - cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| { + cx.on_mouse_event(move |down: &MouseDownEvent, phase, cx| { if phase == DispatchPhase::Bubble { let group = active_group_bounds .map_or(false, |bounds| bounds.contains_point(&down.position)); @@ -1025,7 +996,7 @@ where let line_height = cx.line_height(); let scroll_max = (content_size - bounds.size).max(&Size::default()); - cx.on_mouse_event(move |_, event: &ScrollWheelEvent, phase, cx| { + cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| { if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { let mut scroll_offset = scroll_offset.borrow_mut(); let old_scroll_offset = *scroll_offset; @@ -1063,14 +1034,14 @@ where element_state.focus_handle.clone(), |_, cx| { for listener in self.key_down_listeners.drain(..) { - cx.on_key_event(move |state, event: &KeyDownEvent, phase, cx| { - listener(state, event, phase, cx); + cx.on_key_event(move |event: &KeyDownEvent, phase, cx| { + listener(event, phase, cx); }) } for listener in self.key_up_listeners.drain(..) { - cx.on_key_event(move |state, event: &KeyUpEvent, phase, cx| { - listener(state, event, phase, cx); + cx.on_key_event(move |event: &KeyUpEvent, phase, cx| { + listener(event, phase, cx); }) } @@ -1081,9 +1052,7 @@ where if let Some(focus_handle) = element_state.focus_handle.as_ref() { for listener in self.focus_listeners.drain(..) { let focus_handle = focus_handle.clone(); - cx.on_focus_changed(move |view, event, cx| { - listener(view, &focus_handle, event, cx) - }); + cx.on_focus_changed(move |event, cx| listener(&focus_handle, event, cx)); } } @@ -1100,7 +1069,7 @@ where &self, bounds: Option>, element_state: &mut InteractiveElementState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> Style { let mut style = Style::default(); style.refine(&self.base_style); @@ -1171,7 +1140,7 @@ where } } -impl Default for Interactivity { +impl Default for Interactivity { fn default() -> Self { Self { element_id: None, @@ -1259,31 +1228,25 @@ impl GroupBounds { } } -pub struct Focusable { +pub struct Focusable { element: E, - view_type: PhantomData, } -impl> FocusableComponent for Focusable {} +impl FocusableComponent for Focusable {} -impl InteractiveComponent for Focusable +impl InteractiveComponent for Focusable where - V: 'static, - E: InteractiveComponent, + E: InteractiveComponent, { - fn interactivity(&mut self) -> &mut Interactivity { + fn interactivity(&mut self) -> &mut Interactivity { self.element.interactivity() } } -impl> StatefulInteractiveComponent - for Focusable -{ -} +impl StatefulInteractiveComponent for Focusable {} -impl Styled for Focusable +impl Styled for Focusable where - V: 'static, E: Styled, { fn style(&mut self) -> &mut StyleRefinement { @@ -1291,10 +1254,9 @@ where } } -impl Element for Focusable +impl Element for Focusable where - V: 'static, - E: Element, + E: Element, { type ElementState = E::ElementState; @@ -1304,52 +1266,46 @@ where fn layout( &mut self, - view_state: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> (LayoutId, Self::ElementState) { - self.element.layout(view_state, element_state, cx) + self.element.layout(element_state, cx) } fn paint( &mut self, bounds: Bounds, - view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { - self.element.paint(bounds, view_state, element_state, cx); + self.element.paint(bounds, element_state, cx); } } -impl Component for Focusable +impl Component for Focusable where - V: 'static, - E: 'static + Element, + E: 'static + Element, { - fn render(self) -> AnyElement { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl ParentComponent for Focusable +impl ParentComponent for Focusable where - V: 'static, - E: ParentComponent, + E: ParentComponent, { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { self.element.children_mut() } } -pub struct Stateful { +pub struct Stateful { element: E, - view_type: PhantomData, } -impl Styled for Stateful +impl Styled for Stateful where - V: 'static, E: Styled, { fn style(&mut self) -> &mut StyleRefinement { @@ -1357,30 +1313,27 @@ where } } -impl StatefulInteractiveComponent for Stateful +impl StatefulInteractiveComponent for Stateful where - V: 'static, - E: Element, - Self: InteractiveComponent, + E: Element, + Self: InteractiveComponent, { } -impl InteractiveComponent for Stateful +impl InteractiveComponent for Stateful where - V: 'static, - E: InteractiveComponent, + E: InteractiveComponent, { - fn interactivity(&mut self) -> &mut Interactivity { + fn interactivity(&mut self) -> &mut Interactivity { self.element.interactivity() } } -impl> FocusableComponent for Stateful {} +impl FocusableComponent for Stateful {} -impl Element for Stateful +impl Element for Stateful where - V: 'static, - E: Element, + E: Element, { type ElementState = E::ElementState; @@ -1390,40 +1343,36 @@ where fn layout( &mut self, - view_state: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> (LayoutId, Self::ElementState) { - self.element.layout(view_state, element_state, cx) + self.element.layout(element_state, cx) } fn paint( &mut self, bounds: Bounds, - view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { - self.element.paint(bounds, view_state, element_state, cx) + self.element.paint(bounds, element_state, cx) } } -impl Component for Stateful +impl Component for Stateful where - V: 'static, - E: 'static + Element, + E: 'static + Element, { - fn render(self) -> AnyElement { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl ParentComponent for Stateful +impl ParentComponent for Stateful where - V: 'static, - E: ParentComponent, + E: ParentComponent, { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { self.element.children_mut() } } diff --git a/crates/gpui2/src/elements/img.rs b/crates/gpui2/src/elements/img.rs index 5376c40012..023811dcd2 100644 --- a/crates/gpui2/src/elements/img.rs +++ b/crates/gpui2/src/elements/img.rs @@ -1,18 +1,17 @@ use crate::{ - AnyElement, BorrowWindow, Bounds, Component, Element, InteractiveComponent, - InteractiveElementState, Interactivity, LayoutId, Pixels, SharedString, StyleRefinement, - Styled, ViewContext, + AnyElement, Bounds, Component, Element, InteractiveComponent, InteractiveElementState, + Interactivity, LayoutId, Pixels, SharedString, StyleRefinement, Styled, WindowContext, }; use futures::FutureExt; use util::ResultExt; -pub struct Img { - interactivity: Interactivity, +pub struct Img { + interactivity: Interactivity, uri: Option, grayscale: bool, } -pub fn img() -> Img { +pub fn img() -> Img { Img { interactivity: Interactivity::default(), uri: None, @@ -20,10 +19,7 @@ pub fn img() -> Img { } } -impl Img -where - V: 'static, -{ +impl Img { pub fn uri(mut self, uri: impl Into) -> Self { self.uri = Some(uri.into()); self @@ -35,13 +31,13 @@ where } } -impl Component for Img { - fn render(self) -> AnyElement { +impl Component for Img { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl Element for Img { +impl Element for Img { type ElementState = InteractiveElementState; fn element_id(&self) -> Option { @@ -50,9 +46,8 @@ impl Element for Img { fn layout( &mut self, - _view_state: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> (LayoutId, Self::ElementState) { self.interactivity.layout(element_state, cx, |style, cx| { cx.request_layout(&style, None) @@ -62,9 +57,8 @@ impl Element for Img { fn paint( &mut self, bounds: Bounds, - _view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { self.interactivity.paint( bounds, @@ -89,7 +83,7 @@ impl Element for Img { .log_err() }); } else { - cx.spawn(|_, mut cx| async move { + cx.spawn(|mut cx| async move { if image_future.await.ok().is_some() { cx.on_next_frame(|cx| cx.notify()); } @@ -102,14 +96,14 @@ impl Element for Img { } } -impl Styled for Img { +impl Styled for Img { fn style(&mut self) -> &mut StyleRefinement { &mut self.interactivity.base_style } } -impl InteractiveComponent for Img { - fn interactivity(&mut self) -> &mut Interactivity { +impl InteractiveComponent for Img { + fn interactivity(&mut self) -> &mut Interactivity { &mut self.interactivity } } diff --git a/crates/gpui2/src/elements/overlay.rs b/crates/gpui2/src/elements/overlay.rs index 14a8048d39..19dab158cc 100644 --- a/crates/gpui2/src/elements/overlay.rs +++ b/crates/gpui2/src/elements/overlay.rs @@ -3,15 +3,15 @@ use taffy::style::{Display, Position}; use crate::{ point, AnyElement, BorrowWindow, Bounds, Component, Element, LayoutId, ParentComponent, Pixels, - Point, Size, Style, + Point, Size, Style, WindowContext, }; pub struct OverlayState { child_layout_ids: SmallVec<[LayoutId; 4]>, } -pub struct Overlay { - children: SmallVec<[AnyElement; 2]>, +pub struct Overlay { + children: SmallVec<[AnyElement; 2]>, anchor_corner: AnchorCorner, fit_mode: OverlayFitMode, // todo!(); @@ -21,7 +21,7 @@ pub struct Overlay { /// overlay gives you a floating element that will avoid overflowing the window bounds. /// Its children should have no margin to avoid measurement issues. -pub fn overlay() -> Overlay { +pub fn overlay() -> Overlay { Overlay { children: SmallVec::new(), anchor_corner: AnchorCorner::TopLeft, @@ -30,7 +30,7 @@ pub fn overlay() -> Overlay { } } -impl Overlay { +impl Overlay { /// Sets which corner of the overlay should be anchored to the current position. pub fn anchor(mut self, anchor: AnchorCorner) -> Self { self.anchor_corner = anchor; @@ -51,19 +51,19 @@ impl Overlay { } } -impl ParentComponent for Overlay { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { +impl ParentComponent for Overlay { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { &mut self.children } } -impl Component for Overlay { - fn render(self) -> AnyElement { +impl Component for Overlay { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl Element for Overlay { +impl Element for Overlay { type ElementState = OverlayState; fn element_id(&self) -> Option { @@ -72,14 +72,13 @@ impl Element for Overlay { fn layout( &mut self, - view_state: &mut V, _: Option, - cx: &mut crate::ViewContext, + cx: &mut WindowContext, ) -> (crate::LayoutId, Self::ElementState) { let child_layout_ids = self .children .iter_mut() - .map(|child| child.layout(view_state, cx)) + .map(|child| child.layout(cx)) .collect::>(); let mut overlay_style = Style::default(); @@ -94,9 +93,8 @@ impl Element for Overlay { fn paint( &mut self, bounds: crate::Bounds, - view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut crate::ViewContext, + cx: &mut WindowContext, ) { if element_state.child_layout_ids.is_empty() { return; @@ -157,7 +155,7 @@ impl Element for Overlay { cx.with_element_offset(desired.origin - bounds.origin, |cx| { for child in &mut self.children { - child.paint(view_state, cx); + child.paint(cx); } }) } diff --git a/crates/gpui2/src/elements/svg.rs b/crates/gpui2/src/elements/svg.rs index c1c7691fbf..2a0df36c94 100644 --- a/crates/gpui2/src/elements/svg.rs +++ b/crates/gpui2/src/elements/svg.rs @@ -1,36 +1,36 @@ use crate::{ AnyElement, Bounds, Component, Element, ElementId, InteractiveComponent, InteractiveElementState, Interactivity, LayoutId, Pixels, SharedString, StyleRefinement, - Styled, ViewContext, + Styled, WindowContext, }; use util::ResultExt; -pub struct Svg { - interactivity: Interactivity, +pub struct Svg { + interactivity: Interactivity, path: Option, } -pub fn svg() -> Svg { +pub fn svg() -> Svg { Svg { interactivity: Interactivity::default(), path: None, } } -impl Svg { +impl Svg { pub fn path(mut self, path: impl Into) -> Self { self.path = Some(path.into()); self } } -impl Component for Svg { - fn render(self) -> AnyElement { +impl Component for Svg { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl Element for Svg { +impl Element for Svg { type ElementState = InteractiveElementState; fn element_id(&self) -> Option { @@ -39,9 +39,8 @@ impl Element for Svg { fn layout( &mut self, - _view_state: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> (LayoutId, Self::ElementState) { self.interactivity.layout(element_state, cx, |style, cx| { cx.request_layout(&style, None) @@ -51,9 +50,8 @@ impl Element for Svg { fn paint( &mut self, bounds: Bounds, - _view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) where Self: Sized, { @@ -66,14 +64,14 @@ impl Element for Svg { } } -impl Styled for Svg { +impl Styled for Svg { fn style(&mut self) -> &mut StyleRefinement { &mut self.interactivity.base_style } } -impl InteractiveComponent for Svg { - fn interactivity(&mut self) -> &mut Interactivity { +impl InteractiveComponent for Svg { + fn interactivity(&mut self) -> &mut Interactivity { &mut self.interactivity } } diff --git a/crates/gpui2/src/elements/text.rs b/crates/gpui2/src/elements/text.rs index e3c63523e1..99226baaa7 100644 --- a/crates/gpui2/src/elements/text.rs +++ b/crates/gpui2/src/elements/text.rs @@ -1,6 +1,6 @@ use crate::{ - AnyElement, BorrowWindow, Bounds, Component, Element, ElementId, LayoutId, Pixels, - SharedString, Size, TextRun, ViewContext, WrappedLine, + AnyElement, Bounds, Component, Element, ElementId, LayoutId, Pixels, SharedString, Size, + TextRun, WindowContext, WrappedLine, }; use parking_lot::{Mutex, MutexGuard}; use smallvec::SmallVec; @@ -26,13 +26,13 @@ impl Text { } } -impl Component for Text { - fn render(self) -> AnyElement { +impl Component for Text { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl Element for Text { +impl Element for Text { type ElementState = TextState; fn element_id(&self) -> Option { @@ -41,9 +41,8 @@ impl Element for Text { fn layout( &mut self, - _view: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> (LayoutId, Self::ElementState) { let element_state = element_state.unwrap_or_default(); let text_system = cx.text_system().clone(); @@ -120,9 +119,8 @@ impl Element for Text { fn paint( &mut self, bounds: Bounds, - _: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { let element_state = element_state.lock(); let element_state = element_state @@ -165,7 +163,7 @@ struct InteractiveTextState { clicked_range_ixs: Rc>>, } -impl Element for InteractiveText { +impl Element for InteractiveText { type ElementState = InteractiveTextState; fn element_id(&self) -> Option { @@ -174,23 +172,22 @@ impl Element for InteractiveText { fn layout( &mut self, - view_state: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> (LayoutId, Self::ElementState) { if let Some(InteractiveTextState { text_state, clicked_range_ixs, }) = element_state { - let (layout_id, text_state) = self.text.layout(view_state, Some(text_state), cx); + let (layout_id, text_state) = self.text.layout(Some(text_state), cx); let element_state = InteractiveTextState { text_state, clicked_range_ixs, }; (layout_id, element_state) } else { - let (layout_id, text_state) = self.text.layout(view_state, None, cx); + let (layout_id, text_state) = self.text.layout(None, cx); let element_state = InteractiveTextState { text_state, clicked_range_ixs: Rc::default(), @@ -202,17 +199,15 @@ impl Element for InteractiveText { fn paint( &mut self, bounds: Bounds, - view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { - self.text - .paint(bounds, view_state, &mut element_state.text_state, cx) + self.text.paint(bounds, &mut element_state.text_state, cx) } } -impl Component for SharedString { - fn render(self) -> AnyElement { +impl Component for SharedString { + fn render(self) -> AnyElement { Text { text: self, runs: None, @@ -221,8 +216,8 @@ impl Component for SharedString { } } -impl Component for &'static str { - fn render(self) -> AnyElement { +impl Component for &'static str { + fn render(self) -> AnyElement { Text { text: self.into(), runs: None, @@ -233,8 +228,8 @@ impl Component for &'static str { // TODO: Figure out how to pass `String` to `child` without this. // This impl doesn't exist in the `gpui2` crate. -impl Component for String { - fn render(self) -> AnyElement { +impl Component for String { + fn render(self) -> AnyElement { Text { text: self.into(), runs: None, diff --git a/crates/gpui2/src/elements/uniform_list.rs b/crates/gpui2/src/elements/uniform_list.rs index 773f9ec8aa..48d666383f 100644 --- a/crates/gpui2/src/elements/uniform_list.rs +++ b/crates/gpui2/src/elements/uniform_list.rs @@ -1,7 +1,7 @@ use crate::{ - point, px, size, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, - ElementId, InteractiveComponent, InteractiveElementState, Interactivity, LayoutId, Pixels, - Point, Size, StyleRefinement, Styled, ViewContext, + point, px, size, AnyElement, AvailableSpace, Bounds, Component, Element, ElementId, + InteractiveComponent, InteractiveElementState, Interactivity, LayoutId, Pixels, Point, Size, + StyleRefinement, Styled, WindowContext, }; use smallvec::SmallVec; use std::{cell::RefCell, cmp, mem, ops::Range, rc::Rc}; @@ -10,15 +10,14 @@ use taffy::style::Overflow; /// uniform_list provides lazy rendering for a set of items that are of uniform height. /// When rendered into a container with overflow-y: hidden and a fixed (or max) height, /// uniform_list will only render the visibile subset of items. -pub fn uniform_list( +pub fn uniform_list( id: I, item_count: usize, - f: impl 'static + Fn(&mut V, Range, &mut ViewContext) -> Vec, -) -> UniformList + f: impl 'static + Fn(Range, &mut WindowContext) -> Vec, +) -> UniformList where I: Into, - V: 'static, - C: Component, + C: Component, { let id = id.into(); let mut style = StyleRefinement::default(); @@ -29,8 +28,8 @@ where style, item_count, item_to_measure_index: 0, - render_items: Box::new(move |view, visible_range, cx| { - f(view, visible_range, cx) + render_items: Box::new(move |visible_range, cx| { + f(visible_range, cx) .into_iter() .map(|component| component.render()) .collect() @@ -43,19 +42,14 @@ where } } -pub struct UniformList { +pub struct UniformList { id: ElementId, style: StyleRefinement, item_count: usize, item_to_measure_index: usize, - render_items: Box< - dyn for<'a> Fn( - &'a mut V, - Range, - &'a mut ViewContext, - ) -> SmallVec<[AnyElement; 64]>, - >, - interactivity: Interactivity, + render_items: + Box Fn(Range, &'a mut WindowContext) -> SmallVec<[AnyElement; 64]>>, + interactivity: Interactivity, scroll_handle: Option, } @@ -89,7 +83,7 @@ impl UniformListScrollHandle { } } -impl Styled for UniformList { +impl Styled for UniformList { fn style(&mut self) -> &mut StyleRefinement { &mut self.style } @@ -101,7 +95,7 @@ pub struct UniformListState { item_size: Size, } -impl Element for UniformList { +impl Element for UniformList { type ElementState = UniformListState; fn element_id(&self) -> Option { @@ -110,16 +104,15 @@ impl Element for UniformList { fn layout( &mut self, - view_state: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> (LayoutId, Self::ElementState) { let max_items = self.item_count; let rem_size = cx.rem_size(); let item_size = element_state .as_ref() .map(|s| s.item_size) - .unwrap_or_else(|| self.measure_item(view_state, None, cx)); + .unwrap_or_else(|| self.measure_item(None, cx)); let (layout_id, interactive) = self.interactivity @@ -161,9 +154,8 @@ impl Element for UniformList { fn paint( &mut self, bounds: Bounds, - view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { let style = self.interactivity @@ -209,9 +201,8 @@ impl Element for UniformList { style.paint(bounds, cx); if self.item_count > 0 { - let item_height = self - .measure_item(view_state, Some(padded_bounds.size.width), cx) - .height; + let item_height = + self.measure_item(Some(padded_bounds.size.width), cx).height; if let Some(scroll_handle) = self.scroll_handle.clone() { scroll_handle.0.borrow_mut().replace(ScrollHandleState { item_height, @@ -233,7 +224,7 @@ impl Element for UniformList { self.item_count, ); - let mut items = (self.render_items)(view_state, visible_range.clone(), cx); + let mut items = (self.render_items)(visible_range.clone(), cx); cx.with_z_index(1, |cx| { for (item, ix) in items.iter_mut().zip(visible_range) { let item_origin = padded_bounds.origin @@ -242,7 +233,7 @@ impl Element for UniformList { AvailableSpace::Definite(padded_bounds.size.width), AvailableSpace::Definite(item_height), ); - item.draw(item_origin, available_space, view_state, cx); + item.draw(item_origin, available_space, cx); } }); } @@ -253,24 +244,19 @@ impl Element for UniformList { } } -impl UniformList { +impl UniformList { pub fn with_width_from_item(mut self, item_index: Option) -> Self { self.item_to_measure_index = item_index.unwrap_or(0); self } - fn measure_item( - &self, - view_state: &mut V, - list_width: Option, - cx: &mut ViewContext, - ) -> Size { + fn measure_item(&self, list_width: Option, cx: &mut WindowContext) -> Size { if self.item_count == 0 { return Size::default(); } let item_ix = cmp::min(self.item_to_measure_index, self.item_count - 1); - let mut items = (self.render_items)(view_state, item_ix..item_ix + 1, cx); + let mut items = (self.render_items)(item_ix..item_ix + 1, cx); let mut item_to_measure = items.pop().unwrap(); let available_space = size( list_width.map_or(AvailableSpace::MinContent, |width| { @@ -278,7 +264,7 @@ impl UniformList { }), AvailableSpace::MinContent, ); - item_to_measure.measure(available_space, view_state, cx) + item_to_measure.measure(available_space, cx) } pub fn track_scroll(mut self, handle: UniformListScrollHandle) -> Self { @@ -287,14 +273,14 @@ impl UniformList { } } -impl InteractiveComponent for UniformList { - fn interactivity(&mut self) -> &mut crate::Interactivity { +impl InteractiveComponent for UniformList { + fn interactivity(&mut self) -> &mut crate::Interactivity { &mut self.interactivity } } -impl Component for UniformList { - fn render(self) -> AnyElement { +impl Component for UniformList { + fn render(self) -> AnyElement { AnyElement::new(self) } } diff --git a/crates/gpui2/src/gpui2.rs b/crates/gpui2/src/gpui2.rs index a24509386b..39b148b15b 100644 --- a/crates/gpui2/src/gpui2.rs +++ b/crates/gpui2/src/gpui2.rs @@ -196,6 +196,30 @@ where } } +pub struct CallbackHandle { + callback: Box, +} + +impl From for CallbackHandle { + fn from(value: F) -> Self { + CallbackHandle { + callback: Box::new(value), + } + } +} + +pub struct ConstructorHandle { + callback: Box R + 'static>, +} + +impl R + 'static> From for ConstructorHandle { + fn from(value: F) -> Self { + ConstructorHandle { + callback: Box::new(value), + } + } +} + pub trait Flatten { fn flatten(self) -> Result; } diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index 80a89ef625..2604d24f89 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -1,9 +1,8 @@ use crate::{ - div, point, Component, Div, FocusHandle, Keystroke, Modifiers, Pixels, Point, Render, - ViewContext, + div, point, Div, FocusHandle, Keystroke, Modifiers, Pixels, Point, Render, ViewContext, }; use smallvec::SmallVec; -use std::{any::Any, fmt::Debug, marker::PhantomData, ops::Deref, path::PathBuf}; +use std::{any::Any, fmt::Debug, ops::Deref, path::PathBuf}; #[derive(Clone, Debug, Eq, PartialEq)] pub struct KeyDownEvent { @@ -60,32 +59,6 @@ pub struct ClickEvent { pub up: MouseUpEvent, } -pub struct Drag -where - R: Fn(&mut V, &mut ViewContext) -> E, - V: 'static, - E: Component<()>, -{ - pub state: S, - pub render_drag_handle: R, - view_type: PhantomData, -} - -impl Drag -where - R: Fn(&mut V, &mut ViewContext) -> E, - V: 'static, - E: Component<()>, -{ - pub fn new(state: S, render_drag_handle: R) -> Self { - Drag { - state, - render_drag_handle, - view_type: PhantomData, - } - } -} - #[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)] pub enum MouseButton { Left, @@ -194,7 +167,7 @@ impl Deref for MouseExitEvent { pub struct ExternalPaths(pub(crate) SmallVec<[PathBuf; 2]>); impl Render for ExternalPaths { - type Element = Div; + type Element = Div; fn render(&mut self, _: &mut ViewContext) -> Self::Element { div() // Intentionally left empty because the platform will render icons for the dragged files @@ -287,7 +260,7 @@ pub struct FocusEvent { mod test { use crate::{ self as gpui, div, Component, Div, FocusHandle, InteractiveComponent, KeyBinding, - Keystroke, ParentComponent, Render, Stateful, TestAppContext, ViewContext, VisualContext, + Keystroke, ParentComponent, Render, Stateful, TestAppContext, VisualContext, }; struct TestView { @@ -299,20 +272,24 @@ mod test { actions!(TestAction); impl Render for TestView { - type Element = Stateful>; + type Element = Stateful
; - fn render(&mut self, _: &mut gpui::ViewContext) -> Self::Element { + fn render(&mut self, cx: &mut gpui::ViewContext) -> Self::Element { div().id("testview").child( div() .key_context("parent") - .on_key_down(|this: &mut TestView, _, _, _| this.saw_key_down = true) - .on_action(|this: &mut TestView, _: &TestAction, _| this.saw_action = true) - .child(|this: &mut Self, _cx: &mut ViewContext| { + .on_key_down(cx.callback(|this, _, _| this.saw_key_down = true)) + .on_action( + cx.callback(|this: &mut TestView, _: &TestAction, _| { + this.saw_action = true + }), + ) + .child( div() .key_context("nested") - .track_focus(&this.focus_handle) - .render() - }), + .track_focus(&self.focus_handle) + .render(), + ), ) } } diff --git a/crates/gpui2/src/style.rs b/crates/gpui2/src/style.rs index 1b0cabb401..f958b8b44c 100644 --- a/crates/gpui2/src/style.rs +++ b/crates/gpui2/src/style.rs @@ -2,7 +2,7 @@ use crate::{ black, phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, Font, FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba, - SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext, + SharedString, Size, SizeRefinement, Styled, TextRun, WindowContext, }; use refineable::{Cascade, Refineable}; use smallvec::SmallVec; @@ -313,7 +313,7 @@ impl Style { } /// Paints the background of an element styled with this style. - pub fn paint(&self, bounds: Bounds, cx: &mut ViewContext) { + pub fn paint(&self, bounds: Bounds, cx: &mut WindowContext) { let rem_size = cx.rem_size(); cx.with_z_index(0, |cx| { diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index c1750d6dc5..7bbbbce7af 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -11,7 +11,7 @@ use std::{ }; pub trait Render: 'static + Sized { - type Element: Element + 'static; + type Element: Element + 'static; fn render(&mut self, cx: &mut ViewContext) -> Self::Element; } @@ -67,7 +67,7 @@ impl View { pub fn render_with(&self, component: C) -> RenderViewWith where - C: 'static + Component, + C: 'static + Component, { RenderViewWith { view: self.clone(), @@ -105,8 +105,8 @@ impl PartialEq for View { impl Eq for View {} -impl Component for View { - fn render(self) -> AnyElement { +impl Component for View { + fn render(self) -> AnyElement { AnyElement::new(AnyView::from(self)) } } @@ -211,8 +211,8 @@ impl AnyView { } } -impl Component for AnyView { - fn render(self) -> AnyElement { +impl Component for AnyView { + fn render(self) -> AnyElement { AnyElement::new(self) } } @@ -227,7 +227,7 @@ impl From> for AnyView { } } -impl Element for AnyView { +impl Element for AnyView { type ElementState = Box; fn element_id(&self) -> Option { @@ -236,9 +236,8 @@ impl Element for AnyView { fn layout( &mut self, - _view_state: &mut ParentViewState, _element_state: Option, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> (LayoutId, Self::ElementState) { (self.layout)(self, cx) } @@ -246,9 +245,8 @@ impl Element for AnyView { fn paint( &mut self, _bounds: Bounds, - _view_state: &mut ParentViewState, rendered_element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { (self.paint)(self, rendered_element, cx) } @@ -281,41 +279,39 @@ impl From> for AnyWeakView { } } -// impl Render for T -// where -// T: 'static + FnMut(&mut WindowContext) -> E, -// E: 'static + Send + Element, -// { -// type Element = E; +impl Render for T +where + T: 'static + FnMut(&mut WindowContext) -> E, + E: 'static + Send + Element, +{ + type Element = E; -// fn render(&mut self, cx: &mut ViewContext) -> Self::Element { -// (self)(cx) -// } -// } + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + (self)(cx) + } +} pub struct RenderViewWith { view: View, component: Option, } -impl Component for RenderViewWith +impl Component for RenderViewWith where - C: 'static + Component, - ParentViewState: 'static, - ViewState: 'static, + V: 'static + Render, + C: 'static + Component, { - fn render(self) -> AnyElement { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl Element for RenderViewWith +impl Element for RenderViewWith where - C: 'static + Component, - ParentViewState: 'static, - ViewState: 'static, + V: 'static + Render, + C: 'static + Component, { - type ElementState = AnyElement; + type ElementState = AnyElement; fn element_id(&self) -> Option { Some(self.view.entity_id().into()) @@ -323,25 +319,21 @@ where fn layout( &mut self, - _: &mut ParentViewState, _: Option, - cx: &mut ViewContext, + cx: &mut WindowContext, ) -> (LayoutId, Self::ElementState) { - self.view.update(cx, |view, cx| { - let mut element = self.component.take().unwrap().render(); - let layout_id = element.layout(view, cx); - (layout_id, element) - }) + let mut element = self.component.take().unwrap().render(); + let layout_id = element.layout(cx); + (layout_id, element) } fn paint( &mut self, _: Bounds, - _: &mut ParentViewState, element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { - self.view.update(cx, |view, cx| element.paint(view, cx)) + element.paint(cx) } } @@ -357,7 +349,7 @@ mod any_view { let view = view.clone().downcast::().unwrap(); view.update(cx, |view, cx| { let mut element = AnyElement::new(view.render(cx)); - let layout_id = element.layout(view, cx); + let layout_id = element.layout(cx); (layout_id, Box::new(element) as Box) }) }) @@ -369,9 +361,8 @@ mod any_view { cx: &mut WindowContext, ) { cx.with_element_id(Some(view.model.entity_id), |cx| { - let view = view.clone().downcast::().unwrap(); - let element = element.downcast_mut::>().unwrap(); - view.update(cx, |view, cx| element.paint(view, cx)) + let element = element.downcast_mut::().unwrap(); + element.paint(cx); }) } } diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index a3fe05d39f..d3517996c8 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1,15 +1,15 @@ use crate::{ key_dispatch::DispatchActionListener, px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, - AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle, - DevicePixels, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, - EventEmitter, FileDropEvent, Flatten, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla, - ImageData, InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, LayoutId, Model, - ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, - MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, - PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams, - RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, - Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, - VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS, + AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, CallbackHandle, ConstructorHandle, + Context, Corners, CursorStyle, DevicePixels, DispatchNodeId, DispatchTree, DisplayId, Edges, + Effect, Entity, EntityId, EventEmitter, FileDropEvent, Flatten, FocusEvent, FontId, + GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyBinding, KeyContext, + KeyDownEvent, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, + MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, + PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render, + RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, + SharedString, Size, Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline, + UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::{anyhow, Context as _, Result}; use collections::HashMap; @@ -1436,6 +1436,47 @@ impl<'a> WindowContext<'a> { .dispatch_tree .bindings_for_action(action) } + + ///========== ELEMENT RELATED FUNCTIONS =========== + pub fn with_key_dispatch( + &mut self, + context: KeyContext, + focus_handle: Option, + f: impl FnOnce(Option, &mut Self) -> R, + ) -> R { + let window = &mut self.window; + window + .current_frame + .dispatch_tree + .push_node(context.clone()); + if let Some(focus_handle) = focus_handle.as_ref() { + window + .current_frame + .dispatch_tree + .make_focusable(focus_handle.id); + } + let result = f(focus_handle, self); + + self.window.current_frame.dispatch_tree.pop_node(); + + result + } + + /// Register a focus listener for the current frame only. It will be cleared + /// on the next frame render. You should use this method only from within elements, + /// and we may want to enforce that better via a different context type. + // todo!() Move this to `FrameContext` to emphasize its individuality? + pub fn on_focus_changed( + &mut self, + listener: impl Fn(&FocusEvent, &mut WindowContext) + 'static, + ) { + self.window + .current_frame + .focus_listeners + .push(Box::new(move |event, cx| { + listener(event, cx); + })); + } } impl Context for WindowContext<'_> { @@ -2124,49 +2165,6 @@ impl<'a, V: 'static> ViewContext<'a, V> { ) } - /// Register a focus listener for the current frame only. It will be cleared - /// on the next frame render. You should use this method only from within elements, - /// and we may want to enforce that better via a different context type. - // todo!() Move this to `FrameContext` to emphasize its individuality? - pub fn on_focus_changed( - &mut self, - listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + 'static, - ) { - let handle = self.view().downgrade(); - self.window - .current_frame - .focus_listeners - .push(Box::new(move |event, cx| { - handle - .update(cx, |view, cx| listener(view, event, cx)) - .log_err(); - })); - } - - pub fn with_key_dispatch( - &mut self, - context: KeyContext, - focus_handle: Option, - f: impl FnOnce(Option, &mut Self) -> R, - ) -> R { - let window = &mut self.window; - window - .current_frame - .dispatch_tree - .push_node(context.clone()); - if let Some(focus_handle) = focus_handle.as_ref() { - window - .current_frame - .dispatch_tree - .make_focusable(focus_handle.id); - } - let result = f(focus_handle, self); - - self.window.current_frame.dispatch_tree.pop_node(); - - result - } - pub fn spawn( &mut self, f: impl FnOnce(WeakView, AsyncWindowContext) -> Fut, @@ -2284,6 +2282,25 @@ impl<'a, V: 'static> ViewContext<'a, V> { { self.defer(|_, cx| cx.emit(Manager::Dismiss)) } + + pub fn callback( + &self, + f: impl Fn(&mut V, &E, &mut ViewContext) + 'static, + ) -> CallbackHandle { + let view = self.view().clone(); + (move |e: &E, cx: &mut WindowContext| { + view.update(cx, |view, cx| f(view, e, cx)); + }) + .into() + } + + pub fn constructor( + &self, + f: impl Fn(&mut V, &mut ViewContext) -> R + 'static, + ) -> ConstructorHandle { + let view = self.view().clone(); + (move |cx: &mut WindowContext| view.update(cx, |view, cx| f(view, cx))).into() + } } impl Context for ViewContext<'_, V> {