From 3de8fe0f877ebcc740fe25b82ef138c0d3d66a42 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 10 Apr 2023 17:27:47 -0600 Subject: [PATCH] WIP --- crates/gpui/src/app.rs | 262 +++------ crates/gpui/src/app/test_app_context.rs | 6 +- crates/gpui/src/app/window.rs | 1 + crates/gpui/src/elements.rs | 53 +- crates/gpui/src/elements/canvas.rs | 14 +- crates/gpui/src/elements/container.rs | 2 +- crates/gpui/src/elements/flex.rs | 6 +- crates/gpui/src/elements/list.rs | 515 +++++++++--------- .../gpui/src/elements/mouse_event_handler.rs | 10 +- crates/gpui/src/elements/overlay.rs | 2 +- crates/gpui/src/elements/resizable.rs | 36 +- crates/gpui/src/elements/stack.rs | 38 +- crates/gpui/src/elements/svg.rs | 21 +- crates/gpui/src/elements/text.rs | 27 +- crates/gpui/src/elements/tooltip.rs | 104 ++-- crates/gpui/src/elements/uniform_list.rs | 2 +- crates/gpui/src/gpui.rs | 7 +- crates/gpui/src/scene/mouse_region.rs | 184 ++++--- crates/gpui/src/test.rs | 6 +- crates/gpui/src/text_layout.rs | 9 +- crates/gpui/src/views/select.rs | 64 ++- 21 files changed, 675 insertions(+), 694 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 1582130ba4..70307063e1 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -69,7 +69,7 @@ pub trait Entity: 'static { pub trait View: Entity + Sized { fn ui_name() -> &'static str; - fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox; + fn render(&mut self, cx: &mut ViewContext<'_, '_, Self>) -> ElementBox; fn focus_in(&mut self, _: AnyViewHandle, _: &mut ViewContext) {} fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext) {} fn key_down(&mut self, _: &KeyDownEvent, _: &mut ViewContext) -> bool { @@ -2983,7 +2983,7 @@ where params: RenderParams, cx: &mut WindowContext<'a, 'b>, ) -> Box { - View::render(self, &mut RenderContext::new(params, cx)) + View::render(self, &mut ViewContext::new(params, cx)) } fn focus_in<'a, 'b>( @@ -3359,7 +3359,7 @@ impl<'a, 'b, T: View> DerefMut for ViewContext<'a, 'b, T> { } } -impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { +impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { fn new(window_context: &'b mut WindowContext<'a, 'b>, view_id: usize) -> Self { Self { window_context, @@ -3368,7 +3368,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { } } - pub fn handle(&self) -> ViewHandle { + pub fn handle(&self) -> ViewHandle { ViewHandle::new( self.window_id, self.view_id, @@ -3376,7 +3376,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { ) } - pub fn weak_handle(&self) -> WeakViewHandle { + pub fn weak_handle(&self) -> WeakViewHandle { WeakViewHandle::new(self.window_id, self.view_id) } @@ -3449,7 +3449,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn on_window_should_close(&mut self, mut callback: F) where - F: 'static + FnMut(&mut T, &mut ViewContext) -> bool, + F: 'static + FnMut(&mut V, &mut ViewContext) -> bool, { let window_id = self.window_id(); let view = self.weak_handle(); @@ -3511,10 +3511,10 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { ); } - pub fn replace_root_view(&mut self, build_root_view: F) -> ViewHandle + pub fn replace_root_view(&mut self, build_root_view: F) -> ViewHandle where - V: View, - F: FnOnce(&mut ViewContext) -> V, + W: View, + F: FnOnce(&mut ViewContext) -> W, { let window_id = self.window_id; self.update(|this| { @@ -3533,7 +3533,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { E: Entity, E::Event: 'static, H: Handle, - F: 'static + FnMut(&mut T, H, &E::Event, &mut ViewContext), + F: 'static + FnMut(&mut V, H, &E::Event, &mut ViewContext), { let subscriber = self.weak_handle(); self.window_context @@ -3553,7 +3553,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { where E: Entity, H: Handle, - F: 'static + FnMut(&mut T, H, &mut ViewContext), + F: 'static + FnMut(&mut V, H, &mut ViewContext), { let observer = self.weak_handle(); self.window_context @@ -3572,7 +3572,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn observe_global(&mut self, mut callback: F) -> Subscription where G: Any, - F: 'static + FnMut(&mut T, &mut ViewContext), + F: 'static + FnMut(&mut V, &mut ViewContext), { let observer = self.weak_handle(); self.window_context.observe_global::(move |cx| { @@ -3582,10 +3582,10 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { }) } - pub fn observe_focus(&mut self, handle: &ViewHandle, mut callback: F) -> Subscription + pub fn observe_focus(&mut self, handle: &ViewHandle, mut callback: F) -> Subscription where - F: 'static + FnMut(&mut T, ViewHandle, bool, &mut ViewContext), - V: View, + F: 'static + FnMut(&mut V, ViewHandle, bool, &mut ViewContext), + W: View, { let observer = self.weak_handle(); self.window_context @@ -3605,7 +3605,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { where E: Entity, H: Handle, - F: 'static + FnMut(&mut T, &E, &mut ViewContext), + F: 'static + FnMut(&mut V, &E, &mut ViewContext), { let observer = self.weak_handle(); self.window_context @@ -3620,7 +3620,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn observe_actions(&mut self, mut callback: F) -> Subscription where - F: 'static + FnMut(&mut T, TypeId, &mut ViewContext), + F: 'static + FnMut(&mut V, TypeId, &mut ViewContext), { let observer = self.weak_handle(); self.window_context.observe_actions(move |action_id, cx| { @@ -3634,7 +3634,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn observe_window_activation(&mut self, mut callback: F) -> Subscription where - F: 'static + FnMut(&mut T, bool, &mut ViewContext), + F: 'static + FnMut(&mut V, bool, &mut ViewContext), { let observer = self.weak_handle(); self.window_context @@ -3652,7 +3652,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn observe_fullscreen(&mut self, mut callback: F) -> Subscription where - F: 'static + FnMut(&mut T, bool, &mut ViewContext), + F: 'static + FnMut(&mut V, bool, &mut ViewContext), { let observer = self.weak_handle(); self.window_context @@ -3672,11 +3672,11 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { where F: 'static + FnMut( - &mut T, + &mut V, &Keystroke, Option<&Box>, &MatchResult, - &mut ViewContext, + &mut ViewContext, ) -> bool, { let observer = self.weak_handle(); @@ -3697,7 +3697,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn observe_window_bounds(&mut self, mut callback: F) -> Subscription where - F: 'static + FnMut(&mut T, WindowBounds, Uuid, &mut ViewContext), + F: 'static + FnMut(&mut V, WindowBounds, Uuid, &mut ViewContext), { let observer = self.weak_handle(); self.window_context @@ -3715,7 +3715,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn observe_active_labeled_tasks(&mut self, mut callback: F) -> Subscription where - F: 'static + FnMut(&mut T, &mut ViewContext), + F: 'static + FnMut(&mut V, &mut ViewContext), { let observer = self.weak_handle(); self.window_context.observe_active_labeled_tasks(move |cx| { @@ -3730,7 +3730,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { }) } - pub fn emit(&mut self, payload: T::Event) { + pub fn emit(&mut self, payload: V::Event) { self.window_context .pending_effects .push_back(Effect::Event { @@ -3754,7 +3754,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { .dispatch_any_action_at(self.window_id, self.view_id, action) } - pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut T, &mut ViewContext)) { + pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut V, &mut ViewContext)) { let handle = self.handle(); self.window_context.defer(move |cx| { handle.update(cx, |view, cx| { @@ -3765,7 +3765,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn after_window_update( &mut self, - callback: impl 'static + FnOnce(&mut T, &mut ViewContext), + callback: impl 'static + FnOnce(&mut V, &mut ViewContext), ) { let handle = self.handle(); self.window_context.after_window_update(move |cx| { @@ -3781,7 +3781,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn spawn_labeled(&mut self, task_label: &'static str, f: F) -> Task where - F: FnOnce(ViewHandle, AsyncAppContext) -> Fut, + F: FnOnce(ViewHandle, AsyncAppContext) -> Fut, Fut: 'static + Future, S: 'static, { @@ -3792,7 +3792,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn spawn(&mut self, f: F) -> Task where - F: FnOnce(ViewHandle, AsyncAppContext) -> Fut, + F: FnOnce(ViewHandle, AsyncAppContext) -> Fut, Fut: 'static + Future, S: 'static, { @@ -3802,79 +3802,13 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn spawn_weak(&mut self, f: F) -> Task where - F: FnOnce(WeakViewHandle, AsyncAppContext) -> Fut, + F: FnOnce(WeakViewHandle, AsyncAppContext) -> Fut, Fut: 'static + Future, S: 'static, { let handle = self.weak_handle(); self.window_context.spawn(|cx| f(handle, cx)) } -} - -pub struct RenderParams { - pub window_id: usize, - pub view_id: usize, - pub titlebar_height: f32, - pub hovered_region_ids: HashSet, - pub clicked_region_ids: Option<(HashSet, MouseButton)>, - pub refreshing: bool, - pub appearance: Appearance, -} - -#[derive(Debug, Clone, Default)] -pub struct MouseState { - pub(crate) hovered: bool, - pub(crate) clicked: Option, - pub(crate) accessed_hovered: bool, - pub(crate) accessed_clicked: bool, -} - -impl MouseState { - pub fn hovered(&mut self) -> bool { - self.accessed_hovered = true; - self.hovered - } - - pub fn clicked(&mut self) -> Option { - self.accessed_clicked = true; - self.clicked - } - - pub fn accessed_hovered(&self) -> bool { - self.accessed_hovered - } - - pub fn accessed_clicked(&self) -> bool { - self.accessed_clicked - } -} - -impl<'a, V: View> RenderContext<'a, V> { - fn new(params: RenderParams, app: &'a mut AppContext) -> Self { - Self { - app, - window_id: params.window_id, - view_id: params.view_id, - view_type: PhantomData, - titlebar_height: params.titlebar_height, - hovered_region_ids: params.hovered_region_ids.clone(), - clicked_region_ids: params.clicked_region_ids.clone(), - refreshing: params.refreshing, - appearance: params.appearance, - } - } - - pub fn handle(&self) -> WeakViewHandle { - WeakViewHandle::new(self.window_id, self.view_id) - } - - pub fn window_id(&self) -> usize { - self.window_id - } - - pub fn view_id(&self) -> usize { - self.view_id - } pub fn mouse_state(&self, region_id: usize) -> MouseState { let region_id = MouseRegionId::new::(self.view_id, region_id); @@ -3916,62 +3850,6 @@ impl<'a, V: View> RenderContext<'a, V> { } } -impl Deref for RenderContext<'_, V> { - type Target = AppContext; - - fn deref(&self) -> &Self::Target { - self.app - } -} - -impl DerefMut for RenderContext<'_, V> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.app - } -} - -impl ReadModel for RenderContext<'_, V> { - fn read_model(&self, handle: &ModelHandle) -> &T { - self.app.read_model(handle) - } -} - -impl UpdateModel for RenderContext<'_, V> { - fn update_model( - &mut self, - handle: &ModelHandle, - update: &mut dyn FnMut(&mut T, &mut ModelContext) -> O, - ) -> O { - self.app.update_model(handle, update) - } -} - -impl ReadView for RenderContext<'_, V> { - fn read_view(&self, handle: &ViewHandle) -> &T { - self.app.read_view(handle) - } -} - -impl<'a, 'b, M> Deref for ViewContext<'a, 'b, M> { - type Target = WindowContext<'a, 'b>; - - fn deref(&self) -> &Self::Target { - &self.window_context - } -} - -impl DerefMut for ViewContext<'_, '_, M> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.window_context - } -} - -impl ReadModel for ViewContext<'_, '_, V> { - fn read_model(&self, handle: &ModelHandle) -> &T { - self.window_context.read_model(handle) - } -} - impl UpgradeModelHandle for ViewContext<'_, '_, V> { fn upgrade_model_handle( &self, @@ -3999,16 +3877,6 @@ impl UpgradeViewHandle for ViewContext<'_, '_, V> { } } -impl UpgradeViewHandle for RenderContext<'_, V> { - fn upgrade_view_handle(&self, handle: &WeakViewHandle) -> Option> { - self.app.upgrade_view_handle(handle) - } - - fn upgrade_any_view_handle(&self, handle: &AnyWeakViewHandle) -> Option { - self.app.upgrade_any_view_handle(handle) - } -} - impl UpdateModel for ViewContext<'_, '_, V> { fn update_model( &mut self, @@ -4038,6 +3906,44 @@ impl UpdateView for ViewContext<'_, '_, V> { } } +pub struct RenderParams { + pub window_id: usize, + pub view_id: usize, + pub titlebar_height: f32, + pub hovered_region_ids: HashSet, + pub clicked_region_ids: Option<(HashSet, MouseButton)>, + pub refreshing: bool, + pub appearance: Appearance, +} + +#[derive(Debug, Clone, Default)] +pub struct MouseState { + pub(crate) hovered: bool, + pub(crate) clicked: Option, + pub(crate) accessed_hovered: bool, + pub(crate) accessed_clicked: bool, +} + +impl MouseState { + pub fn hovered(&mut self) -> bool { + self.accessed_hovered = true; + self.hovered + } + + pub fn clicked(&mut self) -> Option { + self.accessed_clicked = true; + self.clicked + } + + pub fn accessed_hovered(&self) -> bool { + self.accessed_hovered + } + + pub fn accessed_clicked(&self) -> bool { + self.accessed_clicked + } +} + pub trait Handle { type Weak: 'static; fn id(&self) -> usize; @@ -5078,7 +4984,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { post_inc(&mut self.render_count); Empty::new().boxed() } @@ -5131,7 +5037,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } @@ -5195,7 +5101,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { enum Handler {} let mouse_down_count = self.mouse_down_count.clone(); MouseEventHandler::::new(0, cx, |_, _| Empty::new().boxed()) @@ -5261,7 +5167,7 @@ mod tests { "View" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } } @@ -5779,7 +5685,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } @@ -5844,7 +5750,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } @@ -6020,7 +5926,7 @@ mod tests { } impl View for ViewA { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } @@ -6038,7 +5944,7 @@ mod tests { } impl View for ViewB { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } @@ -6190,7 +6096,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } @@ -6317,7 +6223,7 @@ mod tests { } impl super::View for View1 { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } fn ui_name() -> &'static str { @@ -6325,7 +6231,7 @@ mod tests { } } impl super::View for View2 { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } fn ui_name() -> &'static str { @@ -6500,7 +6406,7 @@ mod tests { "test view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } } @@ -6562,7 +6468,7 @@ mod tests { "test view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().named(format!("render count: {}", post_inc(&mut self.0))) } } @@ -6651,7 +6557,7 @@ mod tests { "test view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } } @@ -6731,7 +6637,7 @@ mod tests { "child view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { self.rendered.set(true); Empty::new().boxed() } @@ -6756,7 +6662,7 @@ mod tests { "parent view" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if let Some(child) = self.child.as_ref() { ChildView::new(child, cx).boxed() } else { @@ -6798,7 +6704,7 @@ mod tests { "TestView" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } } diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index 560ba66a77..7816b42ac9 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -74,7 +74,7 @@ impl TestAppContext { pub fn dispatch_action(&self, window_id: usize, action: A) { let mut cx = self.cx.borrow_mut(); - if let Some(view_id) = cx.focused_view_id(window_id) { + if let Some(view_id) = cx.focused_view_id { cx.handle_dispatch_action_from_effect(window_id, Some(view_id), &action); } } @@ -169,11 +169,11 @@ impl TestAppContext { pub fn render(&mut self, handle: &ViewHandle, f: F) -> T where - F: FnOnce(&mut V, &mut RenderContext) -> T, + F: FnOnce(&mut V, &mut ViewContext) -> T, V: View, { handle.update(&mut *self.cx.borrow_mut(), |view, cx| { - let mut render_cx = RenderContext { + let mut render_cx = ViewContext { app: cx, window_id: handle.window_id(), view_id: handle.id(), diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 7a167a3c0d..b7a9a0636a 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -87,6 +87,7 @@ pub struct WindowContext<'a: 'b, 'b> { app_context: &'a mut AppContext, pub(crate) window: &'b mut Window, // TODO: make this private? pub(crate) window_id: usize, + pub refreshing: bool, } impl Deref for WindowContext<'_, '_> { diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index e5125e11a8..d23134acaf 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -27,12 +27,11 @@ pub use self::{ }; use self::{clipped::Clipped, expanded::Expanded}; use crate::{ - app::window::MeasurementContext, geometry::{ rect::RectF, vector::{vec2f, Vector2F}, }, - json, Action, RenderContext, SceneBuilder, SizeConstraint, View, ViewContext, + json, Action, SceneBuilder, SizeConstraint, View, ViewContext, }; use core::panic; use json::ToJson; @@ -62,7 +61,7 @@ trait AnyElement { cx: &ViewContext, ) -> Option; - fn debug(&self, view: &V, cx: &mut ViewContext) -> serde_json::Value; + fn debug(&self, view: &V, cx: &ViewContext) -> serde_json::Value; fn size(&self) -> Vector2F; @@ -82,6 +81,7 @@ pub trait Element { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, layout: &mut Self::LayoutState, @@ -133,81 +133,81 @@ pub trait Element { } } - fn constrained(self) -> ConstrainedBox + fn constrained(self) -> ConstrainedBox where Self: 'static + Sized, { ConstrainedBox::new(self.boxed()) } - fn aligned(self) -> Align + fn aligned(self) -> Align where Self: 'static + Sized, { Align::new(self.boxed()) } - fn clipped(self) -> Clipped + fn clipped(self) -> Clipped where Self: 'static + Sized, { Clipped::new(self.boxed()) } - fn contained(self) -> Container + fn contained(self) -> Container where Self: 'static + Sized, { Container::new(self.boxed()) } - fn expanded(self) -> Expanded + fn expanded(self) -> Expanded where Self: 'static + Sized, { Expanded::new(self.boxed()) } - fn flex(self, flex: f32, expanded: bool) -> FlexItem + fn flex(self, flex: f32, expanded: bool) -> FlexItem where Self: 'static + Sized, { FlexItem::new(self.boxed()).flex(flex, expanded) } - fn flex_float(self) -> FlexItem + fn flex_float(self) -> FlexItem where Self: 'static + Sized, { FlexItem::new(self.boxed()).float() } - fn with_tooltip( + fn with_tooltip( self, id: usize, text: String, action: Option>, style: TooltipStyle, - cx: &mut RenderContext, - ) -> Tooltip + cx: &mut ViewContext, + ) -> Tooltip where Self: 'static + Sized, { - Tooltip::new::(id, text, action, style, self.boxed(), cx) + Tooltip::new::(id, text, action, style, self.boxed(), cx) } - fn with_resize_handle( + fn with_resize_handle( self, element_id: usize, side: Side, handle_size: f32, initial_size: f32, - cx: &mut RenderContext, - ) -> Resizable + cx: &mut ViewContext, + ) -> Resizable where Self: 'static + Sized, { - Resizable::new::( + Resizable::new::( self.boxed(), element_id, side, @@ -270,6 +270,7 @@ impl> AnyElement for Lifecycle { fn paint( &mut self, + scene: &mut SceneBuilder, view: &mut V, origin: Vector2F, visible_bounds: RectF, @@ -283,7 +284,7 @@ impl> AnyElement for Lifecycle { mut layout, } => { let bounds = RectF::new(origin, size); - let paint = element.paint(view, bounds, visible_bounds, &mut layout, cx); + let paint = element.paint(scene, bounds, visible_bounds, &mut layout, view, cx); Lifecycle::PostPaint { element, constraint, @@ -301,7 +302,7 @@ impl> AnyElement for Lifecycle { .. } => { let bounds = RectF::new(origin, bounds.size()); - let paint = element.paint(view, bounds, visible_bounds, &mut layout, cx); + let paint = element.paint(scene, bounds, visible_bounds, &mut layout, view, cx); Lifecycle::PostPaint { element, constraint, @@ -334,12 +335,12 @@ impl> AnyElement for Lifecycle { } = self { element.rect_for_text_range( - view, range_utf16, *bounds, *visible_bounds, layout, paint, + view, cx, ) } else { @@ -374,7 +375,7 @@ impl> AnyElement for Lifecycle { layout, paint, } => { - let mut value = element.debug(view, *bounds, layout, paint, cx); + let mut value = element.debug(*bounds, layout, paint, view, cx); if let json::Value::Object(map) = &mut value { let mut new_map: crate::json::Map = Default::default(); @@ -403,7 +404,7 @@ impl> Default for Lifecycle { } pub struct ElementBox { - element: RefCell>, + element: Box>>, view_type: PhantomData, name: Option>, } @@ -420,8 +421,8 @@ impl ElementBox { pub fn layout( &self, - view: &mut V, constraint: SizeConstraint, + view: &mut V, cx: &mut ViewContext, ) -> Vector2F { self.element.borrow_mut().layout(view, constraint, cx) @@ -429,10 +430,10 @@ impl ElementBox { pub fn paint( &self, - view: &mut V, scene: &mut SceneBuilder, origin: Vector2F, visible_bounds: RectF, + view: &mut V, cx: &mut ViewContext, ) { self.element @@ -442,8 +443,8 @@ impl ElementBox { pub fn rect_for_text_range( &self, - view: &V, range_utf16: Range, + view: &V, cx: &ViewContext, ) -> Option { self.element diff --git a/crates/gpui/src/elements/canvas.rs b/crates/gpui/src/elements/canvas.rs index 10d222c506..fb842f92f7 100644 --- a/crates/gpui/src/elements/canvas.rs +++ b/crates/gpui/src/elements/canvas.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use super::Element; use crate::{ json::{self, json}, @@ -9,18 +11,19 @@ use pathfinder_geometry::{ vector::{vec2f, Vector2F}, }; -pub struct Canvas(F); +pub struct Canvas(F, PhantomData); -impl Canvas +impl Canvas where + V: View, F: FnMut(&mut SceneBuilder, RectF, RectF, &mut V, &mut ViewContext), { pub fn new(f: F) -> Self { - Self(f) + Self(f, PhantomData) } } -impl Element for Canvas +impl Element for Canvas where F: FnMut(RectF, RectF, &mut ViewContext), { @@ -30,7 +33,8 @@ where fn layout( &mut self, constraint: crate::SizeConstraint, - _: &mut crate::LayoutContext, + _: &mut V, + _: &mut crate::ViewContext, ) -> (Vector2F, Self::LayoutState) { let x = if constraint.max.x().is_finite() { constraint.max.x() diff --git a/crates/gpui/src/elements/container.rs b/crates/gpui/src/elements/container.rs index 531f893c4f..5631c01bc0 100644 --- a/crates/gpui/src/elements/container.rs +++ b/crates/gpui/src/elements/container.rs @@ -308,7 +308,7 @@ impl Element for Container { _: &Self::LayoutState, _: &Self::PaintState, view: &V, - cx: &crate::DebugContext, + cx: &ViewContext, ) -> serde_json::Value { json!({ "type": "Container", diff --git a/crates/gpui/src/elements/flex.rs b/crates/gpui/src/elements/flex.rs index fff35eb800..31e3f25308 100644 --- a/crates/gpui/src/elements/flex.rs +++ b/crates/gpui/src/elements/flex.rs @@ -101,7 +101,7 @@ impl Flex { vec2f(constraint.max.x(), child_max), ), }; - let child_size = child.layout(child_constraint, cx); + let child_size = child.layout(child_constraint, view, cx); *remaining_space -= child_size.along(self.axis); *remaining_flex -= flex; *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis)); @@ -434,7 +434,7 @@ impl Element for FlexItem { view: &V, cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { - let size = self.child.layout(constraint, cx); + let size = self.child.layout(constraint, view, cx); (size, ()) } @@ -445,7 +445,7 @@ impl Element for FlexItem { visible_bounds: RectF, _: &mut Self::LayoutState, view: &V, - cx: &mut PaintContext, + cx: &mut ViewContext, ) -> Self::PaintState { self.child .paint(scene, bounds.origin(), visible_bounds, view, cx) diff --git a/crates/gpui/src/elements/list.rs b/crates/gpui/src/elements/list.rs index 3adaf1fbae..ef9a202f1a 100644 --- a/crates/gpui/src/elements/list.rs +++ b/crates/gpui/src/elements/list.rs @@ -6,7 +6,7 @@ use crate::{ json::json, Element, ElementBox, MouseRegion, SceneBuilder, SizeConstraint, View, ViewContext, }; -use std::{cell::RefCell, collections::VecDeque, ops::Range, rc::Rc}; +use std::{cell::RefCell, collections::VecDeque, fmt::Debug, ops::Range, rc::Rc}; use sum_tree::{Bias, SumTree}; pub struct List { @@ -24,7 +24,7 @@ pub enum Orientation { struct StateInner { last_layout_width: Option, - render_item: Box) -> Option>>, + render_item: Box) -> ElementBox>, rendered_range: Range, items: SumTree>, logical_scroll_top: Option, @@ -40,14 +40,23 @@ pub struct ListOffset { pub offset_in_item: f32, } -#[derive(Clone)] enum ListItem { Unrendered, Rendered(Rc>), Removed(f32), } -impl std::fmt::Debug for ListItem { +impl Clone for ListItem { + fn clone(&self) -> Self { + match self { + Self::Unrendered => Self::Unrendered, + Self::Rendered(element) => Self::Rendered(element.clone()), + Self::Removed(height) => Self::Removed(*height), + } + } +} + +impl Debug for ListItem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Unrendered => write!(f, "Unrendered"), @@ -245,14 +254,13 @@ impl Element for List { bounds: RectF, visible_bounds: RectF, scroll_top: &mut ListOffset, - view: &V, + view: &mut V, cx: &mut ViewContext, ) { let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default(); - cx.scene.push_layer(Some(visible_bounds)); - - cx.scene.push_mouse_region( - MouseRegion::new::(cx.current_view_id(), 0, bounds).on_scroll({ + scene.push_layer(Some(visible_bounds)); + scene.push_mouse_region( + MouseRegion::new::(cx.view_id(), 0, bounds).on_scroll({ let state = self.state.clone(); let height = bounds.height(); let scroll_top = scroll_top.clone(); @@ -273,7 +281,7 @@ impl Element for List { element.paint(scene, origin, visible_bounds, view, cx); } - cx.scene.pop_layer(); + scene.pop_layer(); } fn rect_for_text_range( @@ -349,9 +357,10 @@ impl ListState { let handle = cx.weak_handle(); Self(Rc::new(RefCell::new(StateInner { last_layout_width: None, - render_item: Box::new(move |ix, cx| { - let handle = handle.upgrade(cx)?; - Some(cx.render(&handle, |view, cx| render_item(view, ix, cx))) + render_item: Box::new(move |ix, view, cx| { + render_item(view, ix, cx) + // let handle = handle.upgrade(cx)?; + // Some(cx.render(&handle, |view, cx| render_item(view, ix, cx))) }), rendered_range: 0..0, items, @@ -442,8 +451,8 @@ impl StateInner { if let Some(ListItem::Rendered(element)) = existing_element { Some(element.clone()) } else { - let mut element = (self.render_item)(ix, cx)?; - element.layout(constraint, cx); + let mut element = (self.render_item)(view, ix, cx); + element.layout(constraint, view, cx); Some(element.into()) } } @@ -460,7 +469,7 @@ impl StateInner { &'a self, bounds: RectF, scroll_top: &ListOffset, - ) -> impl Iterator, Vector2F)> + 'a { + ) -> impl Iterator>, Vector2F)> + 'a { let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item); let mut cursor = self.items.cursor::(); cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &()); @@ -637,262 +646,264 @@ mod tests { #[crate::test(self)] fn test_layout(cx: &mut crate::AppContext) { - let (_, view) = cx.add_window(Default::default(), |_| TestView); - let constraint = SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.)); + todo!() + // let (_, view) = cx.add_window(Default::default(), |_| TestView); + // let constraint = SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.)); - let elements = Rc::new(RefCell::new(vec![(0, 20.), (1, 30.), (2, 100.)])); + // let elements = Rc::new(RefCell::new(vec![(0, 20.), (1, 30.), (2, 100.)])); - let state = view.update(cx, |_, cx| { - ListState::new(elements.borrow().len(), Orientation::Top, 1000.0, cx, { - let elements = elements.clone(); - move |_, ix, _| { - let (id, height) = elements.borrow()[ix]; - TestElement::new(id, height).boxed() - } - }) - }); + // let state = view.update(cx, |_, cx| { + // ListState::new(elements.borrow().len(), Orientation::Top, 1000.0, cx, { + // let elements = elements.clone(); + // move |_, ix, _| { + // let (id, height) = elements.borrow()[ix]; + // TestElement::new(id, height).boxed() + // } + // }) + // }); - let mut list = List::new(state.clone()); - let (size, _) = list.layout( - constraint, - &mut presenter.build_layout_context(vec2f(100., 40.), false, cx), - ); - assert_eq!(size, vec2f(100., 40.)); - assert_eq!( - state.0.borrow().items.summary().clone(), - ListItemSummary { - count: 3, - rendered_count: 3, - unrendered_count: 0, - height: 150. - } - ); + // let mut list = List::new(state.clone()); + // let (size, _) = list.layout( + // constraint, + // &mut presenter.build_layout_context(vec2f(100., 40.), false, cx), + // ); + // assert_eq!(size, vec2f(100., 40.)); + // assert_eq!( + // state.0.borrow().items.summary().clone(), + // ListItemSummary { + // count: 3, + // rendered_count: 3, + // unrendered_count: 0, + // height: 150. + // } + // ); - state.0.borrow_mut().scroll( - &ListOffset { - item_ix: 0, - offset_in_item: 0., - }, - 40., - vec2f(0., -54.), - true, - &mut presenter.build_event_context(&mut Default::default(), cx), - ); - let (_, logical_scroll_top) = list.layout( - constraint, - &mut presenter.build_layout_context(vec2f(100., 40.), false, cx), - ); - assert_eq!( - logical_scroll_top, - ListOffset { - item_ix: 2, - offset_in_item: 4. - } - ); - assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 54.); + // state.0.borrow_mut().scroll( + // &ListOffset { + // item_ix: 0, + // offset_in_item: 0., + // }, + // 40., + // vec2f(0., -54.), + // true, + // &mut presenter.build_event_context(&mut Default::default(), cx), + // ); + // let (_, logical_scroll_top) = list.layout( + // constraint, + // &mut presenter.build_layout_context(vec2f(100., 40.), false, cx), + // ); + // assert_eq!( + // logical_scroll_top, + // ListOffset { + // item_ix: 2, + // offset_in_item: 4. + // } + // ); + // assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 54.); - elements.borrow_mut().splice(1..2, vec![(3, 40.), (4, 50.)]); - elements.borrow_mut().push((5, 60.)); - state.splice(1..2, 2); - state.splice(4..4, 1); - assert_eq!( - state.0.borrow().items.summary().clone(), - ListItemSummary { - count: 5, - rendered_count: 2, - unrendered_count: 3, - height: 120. - } - ); + // elements.borrow_mut().splice(1..2, vec![(3, 40.), (4, 50.)]); + // elements.borrow_mut().push((5, 60.)); + // state.splice(1..2, 2); + // state.splice(4..4, 1); + // assert_eq!( + // state.0.borrow().items.summary().clone(), + // ListItemSummary { + // count: 5, + // rendered_count: 2, + // unrendered_count: 3, + // height: 120. + // } + // ); - let (size, logical_scroll_top) = list.layout( - constraint, - &mut presenter.build_layout_context(vec2f(100., 40.), false, cx), - ); - assert_eq!(size, vec2f(100., 40.)); - assert_eq!( - state.0.borrow().items.summary().clone(), - ListItemSummary { - count: 5, - rendered_count: 5, - unrendered_count: 0, - height: 270. - } - ); - assert_eq!( - logical_scroll_top, - ListOffset { - item_ix: 3, - offset_in_item: 4. - } - ); - assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 114.); + // let (size, logical_scroll_top) = list.layout( + // constraint, + // &mut presenter.build_layout_context(vec2f(100., 40.), false, cx), + // ); + // assert_eq!(size, vec2f(100., 40.)); + // assert_eq!( + // state.0.borrow().items.summary().clone(), + // ListItemSummary { + // count: 5, + // rendered_count: 5, + // unrendered_count: 0, + // height: 270. + // } + // ); + // assert_eq!( + // logical_scroll_top, + // ListOffset { + // item_ix: 3, + // offset_in_item: 4. + // } + // ); + // assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 114.); } #[crate::test(self, iterations = 10, seed = 0)] fn test_random(cx: &mut crate::AppContext, mut rng: StdRng) { - let operations = env::var("OPERATIONS") - .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) - .unwrap_or(10); + todo!() + // let operations = env::var("OPERATIONS") + // .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) + // .unwrap_or(10); - let (window_id, view) = cx.add_window(Default::default(), |_| TestView); - let mut next_id = 0; - let elements = Rc::new(RefCell::new( - (0..rng.gen_range(0..=20)) - .map(|_| { - let id = next_id; - next_id += 1; - (id, rng.gen_range(0..=200) as f32 / 2.0) - }) - .collect::>(), - )); - let orientation = *[Orientation::Top, Orientation::Bottom] - .choose(&mut rng) - .unwrap(); - let overdraw = rng.gen_range(1..=100) as f32; + // let (window_id, view) = cx.add_window(Default::default(), |_| TestView); + // let mut next_id = 0; + // let elements = Rc::new(RefCell::new( + // (0..rng.gen_range(0..=20)) + // .map(|_| { + // let id = next_id; + // next_id += 1; + // (id, rng.gen_range(0..=200) as f32 / 2.0) + // }) + // .collect::>(), + // )); + // let orientation = *[Orientation::Top, Orientation::Bottom] + // .choose(&mut rng) + // .unwrap(); + // let overdraw = rng.gen_range(1..=100) as f32; - let state = view.update(cx, |_, cx| { - ListState::new(elements.borrow().len(), orientation, overdraw, cx, { - let elements = elements.clone(); - move |_, ix, _| { - let (id, height) = elements.borrow()[ix]; - TestElement::new(id, height).boxed() - } - }) - }); + // let state = view.update(cx, |_, cx| { + // ListState::new(elements.borrow().len(), orientation, overdraw, cx, { + // let elements = elements.clone(); + // move |_, ix, _| { + // let (id, height) = elements.borrow()[ix]; + // TestElement::new(id, height).boxed() + // } + // }) + // }); - let mut width = rng.gen_range(0..=2000) as f32 / 2.; - let mut height = rng.gen_range(0..=2000) as f32 / 2.; - log::info!("orientation: {:?}", orientation); - log::info!("overdraw: {}", overdraw); - log::info!("elements: {:?}", elements.borrow()); - log::info!("size: ({:?}, {:?})", width, height); - log::info!("=================="); + // let mut width = rng.gen_range(0..=2000) as f32 / 2.; + // let mut height = rng.gen_range(0..=2000) as f32 / 2.; + // log::info!("orientation: {:?}", orientation); + // log::info!("overdraw: {}", overdraw); + // log::info!("elements: {:?}", elements.borrow()); + // log::info!("size: ({:?}, {:?})", width, height); + // log::info!("=================="); - let mut last_logical_scroll_top = None; - for _ in 0..operations { - match rng.gen_range(0..=100) { - 0..=29 if last_logical_scroll_top.is_some() => { - let delta = vec2f(0., rng.gen_range(-overdraw..=overdraw)); - log::info!( - "Scrolling by {:?}, previous scroll top: {:?}", - delta, - last_logical_scroll_top.unwrap() - ); - state.0.borrow_mut().scroll( - last_logical_scroll_top.as_ref().unwrap(), - height, - delta, - true, - &mut presenter.build_event_context(&mut Default::default(), cx), - ); - } - 30..=34 => { - width = rng.gen_range(0..=2000) as f32 / 2.; - log::info!("changing width: {:?}", width); - } - 35..=54 => { - height = rng.gen_range(0..=1000) as f32 / 2.; - log::info!("changing height: {:?}", height); - } - _ => { - let mut elements = elements.borrow_mut(); - let end_ix = rng.gen_range(0..=elements.len()); - let start_ix = rng.gen_range(0..=end_ix); - let new_elements = (0..rng.gen_range(0..10)) - .map(|_| { - let id = next_id; - next_id += 1; - (id, rng.gen_range(0..=200) as f32 / 2.) - }) - .collect::>(); - log::info!("splice({:?}, {:?})", start_ix..end_ix, new_elements); - state.splice(start_ix..end_ix, new_elements.len()); - elements.splice(start_ix..end_ix, new_elements); - for (ix, item) in state.0.borrow().items.cursor::<()>().enumerate() { - if let ListItem::Rendered(element) = item { - let (expected_id, _) = elements[ix]; - element.with_metadata(|metadata: Option<&usize>| { - assert_eq!(*metadata.unwrap(), expected_id); - }); - } - } - } - } + // let mut last_logical_scroll_top = None; + // for _ in 0..operations { + // match rng.gen_range(0..=100) { + // 0..=29 if last_logical_scroll_top.is_some() => { + // let delta = vec2f(0., rng.gen_range(-overdraw..=overdraw)); + // log::info!( + // "Scrolling by {:?}, previous scroll top: {:?}", + // delta, + // last_logical_scroll_top.unwrap() + // ); + // state.0.borrow_mut().scroll( + // last_logical_scroll_top.as_ref().unwrap(), + // height, + // delta, + // true, + // &mut presenter.build_event_context(&mut Default::default(), cx), + // ); + // } + // 30..=34 => { + // width = rng.gen_range(0..=2000) as f32 / 2.; + // log::info!("changing width: {:?}", width); + // } + // 35..=54 => { + // height = rng.gen_range(0..=1000) as f32 / 2.; + // log::info!("changing height: {:?}", height); + // } + // _ => { + // let mut elements = elements.borrow_mut(); + // let end_ix = rng.gen_range(0..=elements.len()); + // let start_ix = rng.gen_range(0..=end_ix); + // let new_elements = (0..rng.gen_range(0..10)) + // .map(|_| { + // let id = next_id; + // next_id += 1; + // (id, rng.gen_range(0..=200) as f32 / 2.) + // }) + // .collect::>(); + // log::info!("splice({:?}, {:?})", start_ix..end_ix, new_elements); + // state.splice(start_ix..end_ix, new_elements.len()); + // elements.splice(start_ix..end_ix, new_elements); + // for (ix, item) in state.0.borrow().items.cursor::<()>().enumerate() { + // if let ListItem::Rendered(element) = item { + // let (expected_id, _) = elements[ix]; + // element.with_metadata(|metadata: Option<&usize>| { + // assert_eq!(*metadata.unwrap(), expected_id); + // }); + // } + // } + // } + // } - let mut list = List::new(state.clone()); - let window_size = vec2f(width, height); - let (size, logical_scroll_top) = list.layout( - SizeConstraint::new(vec2f(0., 0.), window_size), - &mut presenter.build_layout_context(window_size, false, cx), - ); - assert_eq!(size, window_size); - last_logical_scroll_top = Some(logical_scroll_top); + // let mut list = List::new(state.clone()); + // let window_size = vec2f(width, height); + // let (size, logical_scroll_top) = list.layout( + // SizeConstraint::new(vec2f(0., 0.), window_size), + // &mut presenter.build_layout_context(window_size, false, cx), + // ); + // assert_eq!(size, window_size); + // last_logical_scroll_top = Some(logical_scroll_top); - let state = state.0.borrow(); - log::info!("items {:?}", state.items.items(&())); + // let state = state.0.borrow(); + // log::info!("items {:?}", state.items.items(&())); - let scroll_top = state.scroll_top(&logical_scroll_top); - let rendered_top = (scroll_top - overdraw).max(0.); - let rendered_bottom = scroll_top + height + overdraw; - let mut item_top = 0.; + // let scroll_top = state.scroll_top(&logical_scroll_top); + // let rendered_top = (scroll_top - overdraw).max(0.); + // let rendered_bottom = scroll_top + height + overdraw; + // let mut item_top = 0.; - log::info!( - "rendered top {:?}, rendered bottom {:?}, scroll top {:?}", - rendered_top, - rendered_bottom, - scroll_top, - ); + // log::info!( + // "rendered top {:?}, rendered bottom {:?}, scroll top {:?}", + // rendered_top, + // rendered_bottom, + // scroll_top, + // ); - let mut first_rendered_element_top = None; - let mut last_rendered_element_bottom = None; - assert_eq!(state.items.summary().count, elements.borrow().len()); - for (ix, item) in state.items.cursor::<()>().enumerate() { - match item { - ListItem::Unrendered => { - let item_bottom = item_top; - assert!(item_bottom <= rendered_top || item_top >= rendered_bottom); - item_top = item_bottom; - } - ListItem::Removed(height) => { - let (id, expected_height) = elements.borrow()[ix]; - assert_eq!( - *height, expected_height, - "element {} height didn't match", - id - ); - let item_bottom = item_top + height; - assert!(item_bottom <= rendered_top || item_top >= rendered_bottom); - item_top = item_bottom; - } - ListItem::Rendered(element) => { - let (expected_id, expected_height) = elements.borrow()[ix]; - element.with_metadata(|metadata: Option<&usize>| { - assert_eq!(*metadata.unwrap(), expected_id); - }); - assert_eq!(element.size().y(), expected_height); - let item_bottom = item_top + element.size().y(); - first_rendered_element_top.get_or_insert(item_top); - last_rendered_element_bottom = Some(item_bottom); - assert!(item_bottom > rendered_top || item_top < rendered_bottom); - item_top = item_bottom; - } - } - } + // let mut first_rendered_element_top = None; + // let mut last_rendered_element_bottom = None; + // assert_eq!(state.items.summary().count, elements.borrow().len()); + // for (ix, item) in state.items.cursor::<()>().enumerate() { + // match item { + // ListItem::Unrendered => { + // let item_bottom = item_top; + // assert!(item_bottom <= rendered_top || item_top >= rendered_bottom); + // item_top = item_bottom; + // } + // ListItem::Removed(height) => { + // let (id, expected_height) = elements.borrow()[ix]; + // assert_eq!( + // *height, expected_height, + // "element {} height didn't match", + // id + // ); + // let item_bottom = item_top + height; + // assert!(item_bottom <= rendered_top || item_top >= rendered_bottom); + // item_top = item_bottom; + // } + // ListItem::Rendered(element) => { + // let (expected_id, expected_height) = elements.borrow()[ix]; + // element.with_metadata(|metadata: Option<&usize>| { + // assert_eq!(*metadata.unwrap(), expected_id); + // }); + // assert_eq!(element.size().y(), expected_height); + // let item_bottom = item_top + element.size().y(); + // first_rendered_element_top.get_or_insert(item_top); + // last_rendered_element_bottom = Some(item_bottom); + // assert!(item_bottom > rendered_top || item_top < rendered_bottom); + // item_top = item_bottom; + // } + // } + // } - match orientation { - Orientation::Top => { - if let Some(first_rendered_element_top) = first_rendered_element_top { - assert!(first_rendered_element_top <= scroll_top); - } - } - Orientation::Bottom => { - if let Some(last_rendered_element_bottom) = last_rendered_element_bottom { - assert!(last_rendered_element_bottom >= scroll_top + height); - } - } - } - } + // match orientation { + // Orientation::Top => { + // if let Some(first_rendered_element_top) = first_rendered_element_top { + // assert!(first_rendered_element_top <= scroll_top); + // } + // } + // Orientation::Bottom => { + // if let Some(last_rendered_element_bottom) = last_rendered_element_bottom { + // assert!(last_rendered_element_bottom >= scroll_top + height); + // } + // } + // } + // } } struct TestView; diff --git a/crates/gpui/src/elements/mouse_event_handler.rs b/crates/gpui/src/elements/mouse_event_handler.rs index ba8405f7f5..93515bbc43 100644 --- a/crates/gpui/src/elements/mouse_event_handler.rs +++ b/crates/gpui/src/elements/mouse_event_handler.rs @@ -233,14 +233,16 @@ impl Element for MouseEventHandler { cx: &mut ViewContext, ) -> Self::PaintState { if self.above { - self.child.paint(bounds.origin(), visible_bounds, view, cx); + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx); cx.paint_layer(None, |cx| { - self.paint_regions(bounds, visible_bounds, cx); + self.paint_regions(scene, bounds, visible_bounds, cx); }); } else { - self.paint_regions(bounds, visible_bounds, cx); - self.child.paint(bounds.origin(), visible_bounds, view, cx); + self.paint_regions(scene, bounds, visible_bounds, cx); + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx); } } diff --git a/crates/gpui/src/elements/overlay.rs b/crates/gpui/src/elements/overlay.rs index 0225453ecf..a95667934b 100644 --- a/crates/gpui/src/elements/overlay.rs +++ b/crates/gpui/src/elements/overlay.rs @@ -131,7 +131,7 @@ impl Element for Overlay { } else { constraint }; - let size = self.child.layout(constraint, cx); + let size = self.child.layout(constraint, view, cx); (Vector2F::zero(), size) } diff --git a/crates/gpui/src/elements/resizable.rs b/crates/gpui/src/elements/resizable.rs index d378491f85..33f885bf9b 100644 --- a/crates/gpui/src/elements/resizable.rs +++ b/crates/gpui/src/elements/resizable.rs @@ -7,7 +7,7 @@ use crate::{ geometry::rect::RectF, platform::{CursorStyle, MouseButton}, scene::MouseDrag, - Axis, Element, ElementBox, ElementStateHandle, MouseRegion, RenderContext, View, + Axis, Element, ElementBox, ElementStateHandle, MouseRegion, SceneBuilder, View, ViewContext, }; use super::{ConstrainedBox, Hook}; @@ -75,22 +75,22 @@ struct ResizeHandleState { custom_dimension: Cell, } -pub struct Resizable { +pub struct Resizable { side: Side, handle_size: f32, - child: ElementBox, + child: ElementBox, state: Rc, _state_handle: ElementStateHandle>, } -impl Resizable { +impl Resizable { pub fn new( - child: ElementBox, + child: ElementBox, element_id: usize, side: Side, handle_size: f32, initial_size: f32, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> Self { let state_handle = cx.element_state::>( element_id, @@ -132,24 +132,27 @@ impl Resizable { } } -impl Element for Resizable { +impl Element for Resizable { type LayoutState = (); type PaintState = (); fn layout( &mut self, constraint: crate::SizeConstraint, - cx: &mut crate::LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { - (self.child.layout(constraint, cx), ()) + (self.child.layout(constraint, view, cx), ()) } fn paint( &mut self, + scene: &mut SceneBuilder, bounds: pathfinder_geometry::rect::RectF, visible_bounds: pathfinder_geometry::rect::RectF, _child_size: &mut Self::LayoutState, - cx: &mut crate::PaintContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { cx.scene.push_stacking_context(None, None); @@ -186,7 +189,8 @@ impl Element for Resizable { cx.scene.pop_stacking_context(); - self.child.paint(bounds.origin(), visible_bounds, cx); + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx); } fn rect_for_text_range( @@ -196,9 +200,10 @@ impl Element for Resizable { _visible_bounds: pathfinder_geometry::rect::RectF, _layout: &Self::LayoutState, _paint: &Self::PaintState, - cx: &crate::MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(range_utf16, cx) + self.child.rect_for_text_range(range_utf16, view, cx) } fn debug( @@ -206,10 +211,11 @@ impl Element for Resizable { _bounds: pathfinder_geometry::rect::RectF, _layout: &Self::LayoutState, _paint: &Self::PaintState, - cx: &crate::DebugContext, + view: &V, + cx: &ViewContext, ) -> serde_json::Value { json!({ - "child": self.child.debug(cx), + "child": self.child.debug(view, cx), }) } } diff --git a/crates/gpui/src/elements/stack.rs b/crates/gpui/src/elements/stack.rs index 60f84f53e8..175c5182a7 100644 --- a/crates/gpui/src/elements/stack.rs +++ b/crates/gpui/src/elements/stack.rs @@ -3,41 +3,41 @@ use std::ops::Range; use crate::{ geometry::{rect::RectF, vector::Vector2F}, json::{self, json, ToJson}, - window::MeasurementContext, - DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, + Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext, }; /// Element which renders it's children in a stack on top of each other. /// The first child determines the size of the others. #[derive(Default)] -pub struct Stack { - children: Vec, +pub struct Stack { + children: Vec>, } -impl Stack { +impl Stack { pub fn new() -> Self { Self::default() } } -impl Element for Stack { +impl Element for Stack { type LayoutState = (); type PaintState = (); fn layout( &mut self, mut constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let mut size = constraint.min; let mut children = self.children.iter_mut(); if let Some(bottom_child) = children.next() { - size = bottom_child.layout(constraint, cx); + size = bottom_child.layout(constraint, view, cx); constraint = SizeConstraint::strict(size); } for child in children { - child.layout(constraint, cx); + child.layout(constraint, view, cx); } (size, ()) @@ -45,14 +45,16 @@ impl Element for Stack { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { for child in &mut self.children { cx.paint_layer(None, |cx| { - child.paint(bounds.origin(), visible_bounds, cx); + child.paint(scene, bounds.origin(), visible_bounds, view, cx); }); } } @@ -64,12 +66,13 @@ impl Element for Stack { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { self.children .iter() .rev() - .find_map(|child| child.rect_for_text_range(range_utf16.clone(), cx)) + .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx)) } fn debug( @@ -77,18 +80,19 @@ impl Element for Stack { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &DebugContext, + view: &V, + cx: &ViewContext, ) -> json::Value { json!({ "type": "Stack", "bounds": bounds.to_json(), - "children": self.children.iter().map(|child| child.debug(cx)).collect::>() + "children": self.children.iter().map(|child| child.debug(view, cx)).collect::>() }) } } -impl Extend for Stack { - fn extend>(&mut self, children: T) { +impl Extend> for Stack { + fn extend>>(&mut self, children: T) { self.children.extend(children) } } diff --git a/crates/gpui/src/elements/svg.rs b/crates/gpui/src/elements/svg.rs index dc3e37723b..ace6af7ffa 100644 --- a/crates/gpui/src/elements/svg.rs +++ b/crates/gpui/src/elements/svg.rs @@ -8,9 +8,7 @@ use crate::{ rect::RectF, vector::{vec2f, Vector2F}, }, - scene, - window::MeasurementContext, - DebugContext, Element, LayoutContext, PaintContext, SizeConstraint, + scene, Element, SceneBuilder, SizeConstraint, View, ViewContext, }; pub struct Svg { @@ -32,14 +30,15 @@ impl Svg { } } -impl Element for Svg { +impl Element for Svg { type LayoutState = Option; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { match cx.asset_cache.svg(&self.path) { Ok(tree) => { @@ -59,13 +58,15 @@ impl Element for Svg { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, _visible_bounds: RectF, svg: &mut Self::LayoutState, - cx: &mut PaintContext, + _: &mut V, + _: &mut ViewContext, ) { if let Some(svg) = svg.clone() { - cx.scene.push_icon(scene::Icon { + scene.push_icon(scene::Icon { bounds, svg, path: self.path.clone(), @@ -81,7 +82,8 @@ impl Element for Svg { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &MeasurementContext, + _: &V, + _: &ViewContext, ) -> Option { None } @@ -91,7 +93,8 @@ impl Element for Svg { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &DebugContext, + _: &V, + _: &ViewContext, ) -> serde_json::Value { json!({ "type": "Svg", diff --git a/crates/gpui/src/elements/text.rs b/crates/gpui/src/elements/text.rs index 03ed147cde..6a6a217aee 100644 --- a/crates/gpui/src/elements/text.rs +++ b/crates/gpui/src/elements/text.rs @@ -7,8 +7,7 @@ use crate::{ }, json::{ToJson, Value}, text_layout::{Line, RunStyle, ShapedBoundary}, - window::MeasurementContext, - DebugContext, Element, FontCache, LayoutContext, PaintContext, SizeConstraint, TextLayoutCache, + Element, FontCache, SceneBuilder, SizeConstraint, TextLayoutCache, View, ViewContext, }; use log::warn; use serde_json::json; @@ -53,14 +52,15 @@ impl Text { } } -impl Element for Text { +impl Element for Text { type LayoutState = LayoutState; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + _: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { // Convert the string and highlight ranges into an iterator of highlighted chunks. @@ -99,7 +99,7 @@ impl Element for Text { chunks, &self.style, cx.text_layout_cache, - cx.font_cache, + &cx.font_cache, usize::MAX, self.text.matches('\n').count() + 1, ); @@ -143,10 +143,12 @@ impl Element for Text { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, layout: &mut Self::LayoutState, - cx: &mut PaintContext, + _: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { let mut origin = bounds.origin(); let empty = Vec::new(); @@ -163,6 +165,7 @@ impl Element for Text { if boundaries.intersects(visible_bounds) { if self.soft_wrap { line.paint_wrapped( + scene, origin, visible_bounds, layout.line_height, @@ -170,7 +173,7 @@ impl Element for Text { cx, ); } else { - line.paint(origin, visible_bounds, layout.line_height, cx); + line.paint(scene, origin, visible_bounds, layout.line_height, cx); } } origin.set_y(boundaries.max_y()); @@ -184,7 +187,8 @@ impl Element for Text { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &MeasurementContext, + _: &V, + _: &ViewContext, ) -> Option { None } @@ -194,7 +198,8 @@ impl Element for Text { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &DebugContext, + _: &V, + _: &ViewContext, ) -> Value { json!({ "type": "Text", @@ -272,7 +277,7 @@ pub fn layout_highlighted_chunks<'a>( mod tests { use super::*; use crate::{ - elements::Empty, fonts, platform, AppContext, ElementBox, Entity, RenderContext, View, + elements::Empty, fonts, platform, AppContext, ElementBox, Entity, View, ViewContext, }; #[crate::test(self)] @@ -305,7 +310,7 @@ mod tests { "TestView" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } } diff --git a/crates/gpui/src/elements/tooltip.rs b/crates/gpui/src/elements/tooltip.rs index 971d4bc3e0..39a2a61288 100644 --- a/crates/gpui/src/elements/tooltip.rs +++ b/crates/gpui/src/elements/tooltip.rs @@ -6,9 +6,7 @@ use crate::{ fonts::TextStyle, geometry::{rect::RectF, vector::Vector2F}, json::json, - window::MeasurementContext, - Action, Axis, ElementStateHandle, LayoutContext, PaintContext, RenderContext, SizeConstraint, - Task, View, + Action, Axis, ElementStateHandle, SceneBuilder, SizeConstraint, Task, View, ViewContext, }; use serde::Deserialize; use std::{ @@ -20,9 +18,9 @@ use std::{ const DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(500); -pub struct Tooltip { - child: ElementBox, - tooltip: Option, +pub struct Tooltip { + child: ElementBox, + tooltip: Option>, _state: ElementStateHandle>, } @@ -50,18 +48,19 @@ pub struct KeystrokeStyle { text: TextStyle, } -impl Tooltip { +impl Tooltip { pub fn new( id: usize, text: String, action: Option>, style: TooltipStyle, - child: ElementBox, - cx: &mut RenderContext, + child: ElementBox, + view: &mut V, + cx: &mut ViewContext, ) -> Self { struct ElementState(Tag); struct MouseEventHandlerState(Tag); - let focused_view_id = cx.focused_view_id(cx.window_id); + let focused_view_id = cx.focused_view_id(); let state_handle = cx.default_element_state::, Rc>(id); let state = state_handle.read(cx).clone(); @@ -94,35 +93,36 @@ impl Tooltip { } else { None }; - let child = MouseEventHandler::>::new(id, cx, |_, _| child) - .on_hover(move |e, cx| { - let position = e.position; - let window_id = cx.window_id(); - if let Some(view_id) = cx.view_id() { - if e.started { - if !state.visible.get() { - state.position.set(position); + let child = + MouseEventHandler::>::new(id, view, cx, |_, _| child) + .on_hover(move |e, cx| { + let position = e.position; + let window_id = cx.window_id(); + if let Some(view_id) = cx.view_id() { + if e.started { + if !state.visible.get() { + state.position.set(position); - let mut debounce = state.debounce.borrow_mut(); - if debounce.is_none() { - *debounce = Some(cx.spawn({ - let state = state.clone(); - |mut cx| async move { - cx.background().timer(DEBOUNCE_TIMEOUT).await; - state.visible.set(true); - cx.update(|cx| cx.notify_view(window_id, view_id)); - } - })); + let mut debounce = state.debounce.borrow_mut(); + if debounce.is_none() { + *debounce = Some(cx.spawn({ + let state = state.clone(); + |mut cx| async move { + cx.background().timer(DEBOUNCE_TIMEOUT).await; + state.visible.set(true); + cx.update(|cx| cx.notify_view(window_id, view_id)); + } + })); + } } + } else { + state.visible.set(false); + state.debounce.take(); + cx.notify(); } - } else { - state.visible.set(false); - state.debounce.take(); - cx.notify(); } - } - }) - .boxed(); + }) + .boxed(); Self { child, tooltip, @@ -168,32 +168,40 @@ impl Tooltip { } } -impl Element for Tooltip { +impl Element for Tooltip { type LayoutState = (); type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { - let size = self.child.layout(constraint, cx); + let size = self.child.layout(constraint, view, cx); if let Some(tooltip) = self.tooltip.as_mut() { - tooltip.layout(SizeConstraint::new(Vector2F::zero(), cx.window_size), cx); + tooltip.layout( + SizeConstraint::new(Vector2F::zero(), cx.window_size), + view, + cx, + ); } (size, ()) } fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) { - self.child.paint(bounds.origin(), visible_bounds, cx); + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx); if let Some(tooltip) = self.tooltip.as_mut() { - tooltip.paint(bounds.origin(), visible_bounds, cx); + tooltip.paint(scene, bounds.origin(), visible_bounds, view, cx); } } @@ -204,9 +212,10 @@ impl Element for Tooltip { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(range, cx) + self.child.rect_for_text_range(range, view, cx) } fn debug( @@ -214,11 +223,12 @@ impl Element for Tooltip { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &crate::DebugContext, + view: &V, + cx: &ViewContext, ) -> serde_json::Value { json!({ - "child": self.child.debug(cx), - "tooltip": self.tooltip.as_ref().map(|t| t.debug(cx)), + "child": self.child.debug(view, cx), + "tooltip": self.tooltip.as_ref().map(|t| t.debug(view, cx)), }) } } diff --git a/crates/gpui/src/elements/uniform_list.rs b/crates/gpui/src/elements/uniform_list.rs index c83f83a419..d6eb4f01d1 100644 --- a/crates/gpui/src/elements/uniform_list.rs +++ b/crates/gpui/src/elements/uniform_list.rs @@ -104,7 +104,7 @@ impl UniformList { mut delta: Vector2F, precise: bool, scroll_max: f32, - cx: &mut EventContext, + cx: &mut ViewContext, ) -> bool { if !precise { delta *= 20.; diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index 52ed1197bb..90a4357c5e 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -19,7 +19,7 @@ pub use scene::{Border, CursorRegion, MouseRegion, MouseRegionId, Quad, Scene, S pub mod text_layout; pub use text_layout::TextLayoutCache; mod util; -pub use elements::{Element, ElementBox, ElementRc}; +pub use elements::{Element, ElementBox}; pub mod executor; pub use executor::Task; pub mod color; @@ -27,10 +27,7 @@ pub mod json; pub mod keymap_matcher; pub mod platform; pub use gpui_macros::test; -pub use window::{ - Axis, DebugContext, EventContext, LayoutContext, MeasurementContext, PaintContext, - SizeConstraint, Vector2FExt, -}; +pub use window::{Axis, SizeConstraint, Vector2FExt}; pub use anyhow; pub use serde_json; diff --git a/crates/gpui/src/scene/mouse_region.rs b/crates/gpui/src/scene/mouse_region.rs index e2f8abcf26..ac945af38a 100644 --- a/crates/gpui/src/scene/mouse_region.rs +++ b/crates/gpui/src/scene/mouse_region.rs @@ -5,7 +5,7 @@ use collections::HashMap; use pathfinder_geometry::rect::RectF; use smallvec::SmallVec; -use crate::{platform::MouseButton, EventContext}; +use crate::{platform::MouseButton, window::WindowContext, View, ViewContext}; use super::{ mouse_event::{ @@ -60,82 +60,92 @@ impl MouseRegion { } } - pub fn on_down( - mut self, - button: MouseButton, - handler: impl Fn(MouseDown, &mut EventContext) + 'static, - ) -> Self { + pub fn on_down(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseDown, &mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_down(button, handler); self } - pub fn on_up( - mut self, - button: MouseButton, - handler: impl Fn(MouseUp, &mut EventContext) + 'static, - ) -> Self { + pub fn on_up(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseUp, &mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_up(button, handler); self } - pub fn on_click( - mut self, - button: MouseButton, - handler: impl Fn(MouseClick, &mut EventContext) + 'static, - ) -> Self { + pub fn on_click(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseClick, &mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_click(button, handler); self } - pub fn on_down_out( - mut self, - button: MouseButton, - handler: impl Fn(MouseDownOut, &mut EventContext) + 'static, - ) -> Self { + pub fn on_down_out(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseDownOut, &mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_down_out(button, handler); self } - pub fn on_up_out( - mut self, - button: MouseButton, - handler: impl Fn(MouseUpOut, &mut EventContext) + 'static, - ) -> Self { + pub fn on_up_out(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseUpOut, &mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_up_out(button, handler); self } - pub fn on_drag( - mut self, - button: MouseButton, - handler: impl Fn(MouseDrag, &mut EventContext) + 'static, - ) -> Self { + pub fn on_drag(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseDrag, &mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_drag(button, handler); self } - pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut EventContext) + 'static) -> Self { + pub fn on_hover(mut self, handler: F) -> Self + where + V: View, + F: Fn(&mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_hover(handler); self } - pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut EventContext) + 'static) -> Self { + pub fn on_move(mut self, handler: F) -> Self + where + V: View, + F: Fn(&mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_move(handler); self } - pub fn on_move_out( - mut self, - handler: impl Fn(MouseMoveOut, &mut EventContext) + 'static, - ) -> Self { + pub fn on_move_out(mut self, handler: F) -> Self + where + V: View, + F: Fn(&mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_move_out(handler); self } - pub fn on_scroll( - mut self, - handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static, - ) -> Self { + pub fn on_scroll(mut self, handler: F) -> Self + where + V: View, + F: Fn(&mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_scroll(handler); self } @@ -186,7 +196,7 @@ impl MouseRegionId { } } -pub type HandlerCallback = Rc; +pub type HandlerCallback = Rc; #[derive(Clone, PartialEq, Eq, Hash)] pub struct HandlerKey { @@ -283,7 +293,11 @@ impl HandlerSet { } } - pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut EventContext) + 'static) -> Self { + pub fn on_move(mut self, handler: F) -> Self + where + V: View, + F: Fn(MouseMove, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::move_disc(), None, Rc::new(move |region_event, cx| { if let MouseEvent::Move(e) = region_event { @@ -297,10 +311,11 @@ impl HandlerSet { self } - pub fn on_move_out( - mut self, - handler: impl Fn(MouseMoveOut, &mut EventContext) + 'static, - ) -> Self { + pub fn on_move_out(mut self, handler: F) -> Self + where + V: View, + F: Fn(MouseMoveOut, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::move_out_disc(), None, Rc::new(move |region_event, cx| { if let MouseEvent::MoveOut(e) = region_event { @@ -314,11 +329,11 @@ impl HandlerSet { self } - pub fn on_down( - mut self, - button: MouseButton, - handler: impl Fn(MouseDown, &mut EventContext) + 'static, - ) -> Self { + pub fn on_down(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseDown, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::down_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::Down(e) = region_event { @@ -332,11 +347,11 @@ impl HandlerSet { self } - pub fn on_up( - mut self, - button: MouseButton, - handler: impl Fn(MouseUp, &mut EventContext) + 'static, - ) -> Self { + pub fn on_up(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseUp, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::up_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::Up(e) = region_event { @@ -350,11 +365,11 @@ impl HandlerSet { self } - pub fn on_click( - mut self, - button: MouseButton, - handler: impl Fn(MouseClick, &mut EventContext) + 'static, - ) -> Self { + pub fn on_click(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseClick, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::click_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::Click(e) = region_event { @@ -368,11 +383,11 @@ impl HandlerSet { self } - pub fn on_down_out( - mut self, - button: MouseButton, - handler: impl Fn(MouseDownOut, &mut EventContext) + 'static, - ) -> Self { + pub fn on_down_out(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseDownOut, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::down_out_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::DownOut(e) = region_event { @@ -386,11 +401,11 @@ impl HandlerSet { self } - pub fn on_up_out( - mut self, - button: MouseButton, - handler: impl Fn(MouseUpOut, &mut EventContext) + 'static, - ) -> Self { + pub fn on_up_out(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseUpOut, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::up_out_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::UpOut(e) = region_event { @@ -404,11 +419,11 @@ impl HandlerSet { self } - pub fn on_drag( - mut self, - button: MouseButton, - handler: impl Fn(MouseDrag, &mut EventContext) + 'static, - ) -> Self { + pub fn on_drag(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseDrag, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::drag_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::Drag(e) = region_event { @@ -422,7 +437,11 @@ impl HandlerSet { self } - pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut EventContext) + 'static) -> Self { + pub fn on_hover(mut self, handler: F) -> Self + where + V: View, + F: Fn(MouseHover, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::hover_disc(), None, Rc::new(move |region_event, cx| { if let MouseEvent::Hover(e) = region_event { @@ -436,10 +455,11 @@ impl HandlerSet { self } - pub fn on_scroll( - mut self, - handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static, - ) -> Self { + pub fn on_scroll(mut self, handler: F) -> Self + where + V: View, + F: Fn(MouseScrollWheel, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::scroll_wheel_disc(), None, Rc::new(move |region_event, cx| { if let MouseEvent::ScrollWheel(e) = region_event { diff --git a/crates/gpui/src/test.rs b/crates/gpui/src/test.rs index ce3039f562..97803f43bb 100644 --- a/crates/gpui/src/test.rs +++ b/crates/gpui/src/test.rs @@ -19,8 +19,8 @@ use crate::{ platform, platform::Platform, util::CwdBacktrace, - AppContext, Element, ElementBox, Entity, FontCache, Handle, RenderContext, Subscription, - TestAppContext, View, + AppContext, Element, ElementBox, Entity, FontCache, Handle, Subscription, TestAppContext, View, + ViewContext, }; #[cfg(test)] @@ -240,7 +240,7 @@ impl View for EmptyView { "empty view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Element::boxed(Empty::new()) } } diff --git a/crates/gpui/src/text_layout.rs b/crates/gpui/src/text_layout.rs index 44b1e81c34..8f1b9190a8 100644 --- a/crates/gpui/src/text_layout.rs +++ b/crates/gpui/src/text_layout.rs @@ -9,7 +9,7 @@ use crate::{ platform::FontSystem, scene, window::WindowContext, - AppContext, PaintContext, SceneBuilder, + SceneBuilder, }; use ordered_float::OrderedFloat; use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; @@ -376,11 +376,12 @@ impl Line { pub fn paint_wrapped( &self, + scene: &SceneBuilder, origin: Vector2F, visible_bounds: RectF, line_height: f32, boundaries: impl IntoIterator, - cx: &mut PaintContext, + cx: &mut WindowContext, ) { let padding_top = (line_height - self.layout.ascent - self.layout.descent) / 2.; let baseline_origin = vec2f(0., padding_top + self.layout.ascent); @@ -419,14 +420,14 @@ impl Line { ); if glyph_bounds.intersects(visible_bounds) { if glyph.is_emoji { - cx.scene.push_image_glyph(scene::ImageGlyph { + scene.push_image_glyph(scene::ImageGlyph { font_id: run.font_id, font_size: self.layout.font_size, id: glyph.id, origin: glyph_bounds.origin() + baseline_origin, }); } else { - cx.scene.push_glyph(scene::Glyph { + scene.push_glyph(scene::Glyph { font_id: run.font_id, font_size: self.layout.font_size, id: glyph.id, diff --git a/crates/gpui/src/views/select.rs b/crates/gpui/src/views/select.rs index fc93fce98b..1bfaba4c3b 100644 --- a/crates/gpui/src/views/select.rs +++ b/crates/gpui/src/views/select.rs @@ -1,13 +1,13 @@ use serde::Deserialize; use crate::{ - actions, elements::*, impl_actions, platform::MouseButton, AppContext, Entity, RenderContext, - View, ViewContext, WeakViewHandle, + actions, elements::*, impl_actions, platform::MouseButton, AppContext, Entity, View, + ViewContext, WeakViewHandle, }; pub struct Select { handle: WeakViewHandle, - render_item: Box ElementBox>, + render_item: Box ElementBox>, selected_item_ix: usize, item_count: usize, is_open: bool, @@ -41,7 +41,7 @@ pub fn init(cx: &mut AppContext) { } impl Select { - pub fn new ElementBox>( + pub fn new ElementBox>( item_count: usize, cx: &mut ViewContext, render_item: F, @@ -92,7 +92,7 @@ impl View for Select { "Select" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if self.item_count == 0 { return Empty::new().boxed(); } @@ -106,16 +106,21 @@ impl View for Select { Default::default() }; let mut result = Flex::column().with_child( - MouseEventHandler::
::new(self.handle.id(), cx, |mouse_state, cx| { - Container::new((self.render_item)( - self.selected_item_ix, - ItemType::Header, - mouse_state.hovered(), - cx, - )) - .with_style(style.header) - .boxed() - }) + MouseEventHandler::
::new( + self.handle.id(), + self, + cx, + |mouse_state, this, cx| { + Container::new((self.render_item)( + self.selected_item_ix, + ItemType::Header, + mouse_state.hovered(), + cx, + )) + .with_style(style.header) + .boxed() + }, + ) .on_click(MouseButton::Left, move |_, cx| { cx.dispatch_action(ToggleSelect) }) @@ -134,18 +139,23 @@ impl View for Select { let selected_item_ix = this.selected_item_ix; range.end = range.end.min(this.item_count); items.extend(range.map(|ix| { - MouseEventHandler::::new(ix, cx, |mouse_state, cx| { - (this.render_item)( - ix, - if ix == selected_item_ix { - ItemType::Selected - } else { - ItemType::Unselected - }, - mouse_state.hovered(), - cx, - ) - }) + MouseEventHandler::::new( + ix, + self, + cx, + |mouse_state, this, cx| { + (this.render_item)( + ix, + if ix == selected_item_ix { + ItemType::Selected + } else { + ItemType::Unselected + }, + mouse_state.hovered(), + cx, + ) + }, + ) .on_click(MouseButton::Left, move |_, cx| { cx.dispatch_action(SelectItem(ix)) })