diff --git a/Cargo.lock b/Cargo.lock index d05d3535e8..74769a3d6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -757,6 +757,7 @@ dependencies = [ "pathfinder_geometry", "pin-project", "rand 0.8.3", + "replace_with", "smallvec", "smol", "tree-sitter", @@ -1259,6 +1260,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "replace_with" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a8614ee435691de62bcffcf4a66d91b3594bf1428a5722e79103249a095690" + [[package]] name = "rust-argon2" version = "0.8.3" diff --git a/gpui/Cargo.toml b/gpui/Cargo.toml index aa8b5650b8..e58f493d6f 100644 --- a/gpui/Cargo.toml +++ b/gpui/Cargo.toml @@ -14,6 +14,7 @@ pathfinder_color = "0.5" pathfinder_geometry = "0.5" pin-project = "1.0.5" rand = "0.8.3" +replace_with = "0.1.7" smallvec = "1.6.1" smol = "1.2" tree-sitter = "0.17" diff --git a/gpui/src/app.rs b/gpui/src/app.rs index c4e5f789c1..9183ce1b7d 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -1,5 +1,5 @@ use crate::{ - elements::Element, + elements::ElementBox, executor::{self, ForegroundTask}, keymap::{self, Keystroke}, platform::{self, App as _, WindowOptions}, @@ -30,7 +30,7 @@ pub trait Entity: 'static + Send + Sync { pub trait View: Entity { fn ui_name() -> &'static str; - fn render<'a>(&self, app: &AppContext) -> Box; + fn render<'a>(&self, app: &AppContext) -> ElementBox; fn on_focus(&mut self, _ctx: &mut ViewContext) {} fn on_blur(&mut self, _ctx: &mut ViewContext) {} fn keymap_context(&self, _: &AppContext) -> keymap::Context { @@ -458,11 +458,11 @@ impl MutableAppContext { self.ctx.focused_view_id(window_id) } - pub fn render_view(&self, window_id: usize, view_id: usize) -> Result> { + pub fn render_view(&self, window_id: usize, view_id: usize) -> Result { self.ctx.render_view(window_id, view_id) } - pub fn render_views(&self, window_id: usize) -> Result>> { + pub fn render_views(&self, window_id: usize) -> Result> { self.ctx.render_views(window_id) } @@ -545,13 +545,6 @@ impl MutableAppContext { responder_chain: Vec, keystroke: &Keystroke, ) -> Result { - log::info!( - "dispatch_keystroke {} {:?} {:?}", - window_id, - responder_chain, - keystroke - ); - let mut context_chain = Vec::new(); let mut context = keymap::Context::default(); for view_id in &responder_chain { @@ -641,7 +634,6 @@ impl MutableAppContext { let mut app = self.upgrade(); let presenter = presenter.clone(); window.on_event(Box::new(move |event| { - log::info!("event {:?}", event); app.update(|ctx| { if let Event::KeyDown { keystroke, .. } = &event { if ctx @@ -687,7 +679,6 @@ impl MutableAppContext { } self.on_window_invalidated(window_id, move |invalidation, ctx| { - log::info!("window invalidated"); let mut presenter = presenter.borrow_mut(); presenter.invalidate(invalidation, ctx.downgrade()); let scene = presenter.build_scene(window.size(), window.scale_factor(), ctx); @@ -1285,7 +1276,7 @@ impl AppContext { .and_then(|window| window.focused_view) } - pub fn render_view(&self, window_id: usize, view_id: usize) -> Result> { + pub fn render_view(&self, window_id: usize, view_id: usize) -> Result { self.windows .get(&window_id) .and_then(|w| w.views.get(&view_id)) @@ -1293,14 +1284,14 @@ impl AppContext { .ok_or(anyhow!("view not found")) } - pub fn render_views(&self, window_id: usize) -> Result>> { + pub fn render_views(&self, window_id: usize) -> Result> { self.windows .get(&window_id) .map(|w| { w.views .iter() .map(|(id, view)| (*id, view.render(self))) - .collect::>>() + .collect::>() }) .ok_or(anyhow!("window not found")) } @@ -1388,7 +1379,7 @@ pub trait AnyView: Send + Sync { fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; fn ui_name(&self) -> &'static str; - fn render<'a>(&self, app: &AppContext) -> Box; + fn render<'a>(&self, app: &AppContext) -> ElementBox; fn on_focus(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize); fn on_blur(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize); fn keymap_context(&self, app: &AppContext) -> keymap::Context; @@ -1410,7 +1401,7 @@ where T::ui_name() } - fn render<'a>(&self, app: &AppContext) -> Box { + fn render<'a>(&self, app: &AppContext) -> ElementBox { View::render(self, app) } @@ -2556,7 +2547,7 @@ mod tests { } impl super::View for View { - fn render<'a>(&self, _: &AppContext) -> Box { + fn render<'a>(&self, _: &AppContext) -> ElementBox { Empty::new().boxed() } @@ -2628,7 +2619,7 @@ mod tests { } impl super::View for View { - fn render<'a>(&self, _: &AppContext) -> Box { + fn render<'a>(&self, _: &AppContext) -> ElementBox { Empty::new().boxed() } @@ -2684,7 +2675,7 @@ mod tests { } impl super::View for View { - fn render<'a>(&self, _: &AppContext) -> Box { + fn render<'a>(&self, _: &AppContext) -> ElementBox { Empty::new().boxed() } @@ -2738,7 +2729,7 @@ mod tests { } impl super::View for View { - fn render<'a>(&self, _: &AppContext) -> Box { + fn render<'a>(&self, _: &AppContext) -> ElementBox { Empty::new().boxed() } @@ -2784,7 +2775,7 @@ mod tests { } impl super::View for View { - fn render<'a>(&self, _: &AppContext) -> Box { + fn render<'a>(&self, _: &AppContext) -> ElementBox { Empty::new().boxed() } @@ -2835,7 +2826,7 @@ mod tests { } impl super::View for View { - fn render<'a>(&self, _: &AppContext) -> Box { + fn render<'a>(&self, _: &AppContext) -> ElementBox { Empty::new().boxed() } @@ -2897,7 +2888,7 @@ mod tests { } impl super::View for View { - fn render<'a>(&self, _: &AppContext) -> Box { + fn render<'a>(&self, _: &AppContext) -> ElementBox { Empty::new().boxed() } @@ -2939,7 +2930,7 @@ mod tests { } impl super::View for View { - fn render<'a>(&self, _: &AppContext) -> Box { + fn render<'a>(&self, _: &AppContext) -> ElementBox { Empty::new().boxed() } @@ -2981,7 +2972,7 @@ mod tests { } impl View for ViewA { - fn render<'a>(&self, _: &AppContext) -> Box { + fn render<'a>(&self, _: &AppContext) -> ElementBox { Empty::new().boxed() } @@ -2999,7 +2990,7 @@ mod tests { } impl View for ViewB { - fn render<'a>(&self, _: &AppContext) -> Box { + fn render<'a>(&self, _: &AppContext) -> ElementBox { Empty::new().boxed() } @@ -3104,7 +3095,7 @@ mod tests { } impl super::View for View { - fn render<'a>(&self, _: &AppContext) -> Box { + fn render<'a>(&self, _: &AppContext) -> ElementBox { Empty::new().boxed() } @@ -3174,7 +3165,7 @@ mod tests { // } // impl super::View for View { - // fn render<'a>(&self, _: &AppContext) -> Box { + // fn render<'a>(&self, _: &AppContext) -> ElementBox { // Empty::new().boxed() // } @@ -3253,7 +3244,7 @@ mod tests { } impl super::View for View { - fn render<'a>(&self, _: &AppContext) -> Box { + fn render<'a>(&self, _: &AppContext) -> ElementBox { Empty::new().boxed() } diff --git a/gpui/src/elements/align.rs b/gpui/src/elements/align.rs index 3f9189c967..a8277d2469 100644 --- a/gpui/src/elements/align.rs +++ b/gpui/src/elements/align.rs @@ -1,21 +1,19 @@ use crate::{ - AfterLayoutContext, AppContext, Element, Event, EventContext, LayoutContext, MutableAppContext, - PaintContext, SizeConstraint, + AfterLayoutContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, + SizeConstraint, }; use pathfinder_geometry::vector::{vec2f, Vector2F}; pub struct Align { - child: Box, + child: ElementBox, alignment: Vector2F, - size: Option, } impl Align { - pub fn new(child: Box) -> Self { + pub fn new(child: ElementBox) -> Self { Self { child, alignment: Vector2F::zero(), - size: None, } } @@ -26,43 +24,59 @@ impl Align { } impl Element for Align { + type LayoutState = (); + type PaintState = (); + fn layout( &mut self, mut constraint: SizeConstraint, ctx: &mut LayoutContext, - app: &AppContext, - ) -> Vector2F { + ) -> (Vector2F, Self::LayoutState) { let mut size = constraint.max; constraint.min = Vector2F::zero(); - let child_size = self.child.layout(constraint, ctx, app); + let child_size = self.child.layout(constraint, ctx); if size.x().is_infinite() { size.set_x(child_size.x()); } if size.y().is_infinite() { size.set_y(child_size.y()); } - self.size = Some(size); - size + (size, ()) } - fn after_layout(&mut self, ctx: &mut AfterLayoutContext, app: &mut MutableAppContext) { - self.child.after_layout(ctx, app); + fn after_layout( + &mut self, + _: Vector2F, + _: &mut Self::LayoutState, + ctx: &mut AfterLayoutContext, + ) { + self.child.after_layout(ctx); } - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) { - let self_center = self.size.unwrap() / 2.0; - let self_target = self_center + self_center * self.alignment; - let child_center = self.child.size().unwrap() / 2.0; + fn paint( + &mut self, + bounds: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + ctx: &mut PaintContext, + ) -> Self::PaintState { + let my_center = bounds.size() / 2.; + let my_target = my_center + my_center * self.alignment; + + let child_center = self.child.size() / 2.; let child_target = child_center + child_center * self.alignment; - let origin = origin - (child_target - self_target); - self.child.paint(origin, ctx, app); + + self.child + .paint(bounds.origin() - (child_target - my_target), ctx); } - fn dispatch_event(&self, event: &Event, ctx: &mut EventContext, app: &AppContext) -> bool { - self.child.dispatch_event(event, ctx, app) - } - - fn size(&self) -> Option { - self.size + fn dispatch_event( + &mut self, + event: &Event, + _: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + _: &mut Self::PaintState, + ctx: &mut EventContext, + ) -> bool { + self.child.dispatch_event(event, ctx) } } diff --git a/gpui/src/elements/constrained_box.rs b/gpui/src/elements/constrained_box.rs index a4a06598d8..dc4c0be7fd 100644 --- a/gpui/src/elements/constrained_box.rs +++ b/gpui/src/elements/constrained_box.rs @@ -1,16 +1,16 @@ use crate::{ - AfterLayoutContext, AppContext, Element, Event, EventContext, LayoutContext, MutableAppContext, - PaintContext, SizeConstraint, + AfterLayoutContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, + SizeConstraint, }; use pathfinder_geometry::vector::Vector2F; pub struct ConstrainedBox { - child: Box, + child: ElementBox, constraint: SizeConstraint, } impl ConstrainedBox { - pub fn new(child: Box) -> Self { + pub fn new(child: ElementBox) -> Self { Self { child, constraint: SizeConstraint { @@ -38,30 +38,46 @@ impl ConstrainedBox { } impl Element for ConstrainedBox { + type LayoutState = (); + type PaintState = (); + fn layout( &mut self, mut constraint: SizeConstraint, ctx: &mut LayoutContext, - app: &AppContext, - ) -> Vector2F { + ) -> (Vector2F, Self::LayoutState) { constraint.min = constraint.min.max(self.constraint.min); constraint.max = constraint.max.min(self.constraint.max); - self.child.layout(constraint, ctx, app) + let size = self.child.layout(constraint, ctx); + (size, ()) } - fn after_layout(&mut self, ctx: &mut AfterLayoutContext, app: &mut MutableAppContext) { - self.child.after_layout(ctx, app); + fn after_layout( + &mut self, + _: Vector2F, + _: &mut Self::LayoutState, + ctx: &mut AfterLayoutContext, + ) { + self.child.after_layout(ctx); } - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) { - self.child.paint(origin, ctx, app); + fn paint( + &mut self, + bounds: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + ctx: &mut PaintContext, + ) -> Self::PaintState { + self.child.paint(bounds.origin(), ctx); } - fn dispatch_event(&self, event: &Event, ctx: &mut EventContext, app: &AppContext) -> bool { - self.child.dispatch_event(event, ctx, app) - } - - fn size(&self) -> Option { - self.child.size() + fn dispatch_event( + &mut self, + event: &Event, + _: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + _: &mut Self::PaintState, + ctx: &mut EventContext, + ) -> bool { + self.child.dispatch_event(event, ctx) } } diff --git a/gpui/src/elements/container.rs b/gpui/src/elements/container.rs index 0fbd48be1f..0f00cb17c1 100644 --- a/gpui/src/elements/container.rs +++ b/gpui/src/elements/container.rs @@ -4,8 +4,8 @@ use crate::{ color::ColorU, geometry::vector::{vec2f, Vector2F}, scene::{Border, Quad}, - AfterLayoutContext, AppContext, Element, Event, EventContext, LayoutContext, MutableAppContext, - PaintContext, SizeConstraint, + AfterLayoutContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, + SizeConstraint, }; pub struct Container { @@ -16,13 +16,11 @@ pub struct Container { border: Border, corner_radius: f32, shadow: Option, - child: Box, - size: Option, - origin: Option, + child: ElementBox, } impl Container { - pub fn new(child: Box) -> Self { + pub fn new(child: ElementBox) -> Self { Self { margin: Margin::default(), padding: Padding::default(), @@ -32,8 +30,6 @@ impl Container { corner_radius: 0.0, shadow: None, child, - size: None, - origin: None, } } @@ -122,43 +118,56 @@ impl Container { } impl Element for Container { + type LayoutState = (); + type PaintState = (); + fn layout( &mut self, constraint: SizeConstraint, ctx: &mut LayoutContext, - app: &AppContext, - ) -> Vector2F { + ) -> (Vector2F, Self::LayoutState) { let size_buffer = self.margin_size() + self.padding_size() + self.border_size(); let child_constraint = SizeConstraint { min: (constraint.min - size_buffer).max(Vector2F::zero()), max: (constraint.max - size_buffer).max(Vector2F::zero()), }; - let child_size = self.child.layout(child_constraint, ctx, app); - let size = child_size + size_buffer; - self.size = Some(size); - size + let child_size = self.child.layout(child_constraint, ctx); + (child_size + size_buffer, ()) } - fn after_layout(&mut self, ctx: &mut AfterLayoutContext, app: &mut MutableAppContext) { - self.child.after_layout(ctx, app); + fn after_layout( + &mut self, + _: Vector2F, + _: &mut Self::LayoutState, + ctx: &mut AfterLayoutContext, + ) { + self.child.after_layout(ctx); } - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) { + fn paint( + &mut self, + bounds: RectF, + _: &mut Self::LayoutState, + ctx: &mut PaintContext, + ) -> Self::PaintState { ctx.scene.push_quad(Quad { - bounds: RectF::new(origin, self.size.unwrap()), + bounds, background: self.background_color, border: self.border, corner_radius: self.corner_radius, }); - self.child.paint(origin, ctx, app); + self.child.paint(bounds.origin(), ctx); } - fn dispatch_event(&self, event: &Event, ctx: &mut EventContext, app: &AppContext) -> bool { - self.child.dispatch_event(event, ctx, app) - } - - fn size(&self) -> Option { - self.size + fn dispatch_event( + &mut self, + event: &Event, + _: RectF, + _: &mut Self::LayoutState, + _: &mut Self::PaintState, + ctx: &mut EventContext, + ) -> bool { + self.child.dispatch_event(event, ctx) } } diff --git a/gpui/src/elements/empty.rs b/gpui/src/elements/empty.rs index 75db1ffa9e..330b77ae4b 100644 --- a/gpui/src/elements/empty.rs +++ b/gpui/src/elements/empty.rs @@ -1,45 +1,47 @@ use crate::{ - AfterLayoutContext, AppContext, Element, Event, EventContext, LayoutContext, MutableAppContext, - PaintContext, SizeConstraint, + AfterLayoutContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint, }; -use pathfinder_geometry::vector::Vector2F; +use pathfinder_geometry::{rect::RectF, vector::Vector2F}; -pub struct Empty { - size: Option, - origin: Option, -} +pub struct Empty; impl Empty { pub fn new() -> Self { - Self { - size: None, - origin: None, - } + Self } } impl Element for Empty { + type LayoutState = (); + type PaintState = (); + fn layout( &mut self, constraint: SizeConstraint, _: &mut LayoutContext, - _: &AppContext, - ) -> Vector2F { - self.size = Some(constraint.max); - constraint.max + ) -> (Vector2F, Self::LayoutState) { + (constraint.max, ()) } - fn after_layout(&mut self, _: &mut AfterLayoutContext, _: &mut MutableAppContext) {} - - fn paint(&mut self, origin: Vector2F, _: &mut PaintContext, _: &AppContext) { - self.origin = Some(origin); + fn after_layout(&mut self, _: Vector2F, _: &mut Self::LayoutState, _: &mut AfterLayoutContext) { } - fn dispatch_event(&self, _: &Event, _: &mut EventContext, _: &AppContext) -> bool { + fn paint( + &mut self, + _: RectF, + _: &mut Self::LayoutState, + _: &mut PaintContext, + ) -> Self::PaintState { + } + + fn dispatch_event( + &mut self, + _: &Event, + _: RectF, + _: &mut Self::LayoutState, + _: &mut Self::PaintState, + _: &mut EventContext, + ) -> bool { false } - - fn size(&self) -> Option { - self.size - } } diff --git a/gpui/src/elements/event_handler.rs b/gpui/src/elements/event_handler.rs index eed03ca54b..b558bd0254 100644 --- a/gpui/src/elements/event_handler.rs +++ b/gpui/src/elements/event_handler.rs @@ -1,69 +1,83 @@ -use super::try_rect; use crate::{ - geometry::vector::Vector2F, AfterLayoutContext, AppContext, Element, Event, EventContext, - LayoutContext, MutableAppContext, PaintContext, SizeConstraint, + geometry::vector::Vector2F, AfterLayoutContext, Element, ElementBox, Event, EventContext, + LayoutContext, PaintContext, SizeConstraint, }; -use std::cell::RefCell; pub struct EventHandler { - child: Box, - mouse_down: Option bool>>>, - origin: Option, + child: ElementBox, + mouse_down: Option bool>>, } impl EventHandler { - pub fn new(child: Box) -> Self { + pub fn new(child: ElementBox) -> Self { Self { child, mouse_down: None, - origin: None, } } pub fn on_mouse_down(mut self, callback: F) -> Self where - F: 'static + FnMut(&mut EventContext, &AppContext) -> bool, + F: 'static + FnMut(&mut EventContext) -> bool, { - self.mouse_down = Some(RefCell::new(Box::new(callback))); + self.mouse_down = Some(Box::new(callback)); self } } impl Element for EventHandler { + type LayoutState = (); + type PaintState = (); + fn layout( &mut self, constraint: SizeConstraint, ctx: &mut LayoutContext, - app: &AppContext, - ) -> Vector2F { - self.child.layout(constraint, ctx, app) + ) -> (Vector2F, Self::LayoutState) { + let size = self.child.layout(constraint, ctx); + (size, ()) } - fn after_layout(&mut self, ctx: &mut AfterLayoutContext, app: &mut MutableAppContext) { - self.child.after_layout(ctx, app); + fn after_layout( + &mut self, + _: Vector2F, + _: &mut Self::LayoutState, + ctx: &mut AfterLayoutContext, + ) { + self.child.after_layout(ctx); } - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) { - self.origin = Some(origin); - self.child.paint(origin, ctx, app); + fn paint( + &mut self, + bounds: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + ctx: &mut PaintContext, + ) -> Self::PaintState { + self.child.paint(bounds.origin(), ctx); } - fn size(&self) -> Option { - self.child.size() - } - - fn dispatch_event(&self, event: &Event, ctx: &mut EventContext, app: &AppContext) -> bool { - match event { - Event::LeftMouseDown { position, .. } => { - if let Some(callback) = self.mouse_down.as_ref() { - let rect = try_rect(self.origin, self.size()).unwrap(); - if rect.contains_point(*position) { - return callback.borrow_mut()(ctx, app); + fn dispatch_event( + &mut self, + event: &Event, + bounds: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + _: &mut Self::PaintState, + ctx: &mut EventContext, + ) -> bool { + if self.child.dispatch_event(event, ctx) { + true + } else { + match event { + Event::LeftMouseDown { position, .. } => { + if let Some(callback) = self.mouse_down.as_mut() { + if bounds.contains_point(*position) { + return callback(ctx); + } } + false } - false + _ => false, } - _ => false, } } } diff --git a/gpui/src/elements/flex.rs b/gpui/src/elements/flex.rs index d2eab3483b..86cc9447c5 100644 --- a/gpui/src/elements/flex.rs +++ b/gpui/src/elements/flex.rs @@ -1,15 +1,14 @@ +use std::any::Any; + use crate::{ - AfterLayoutContext, AppContext, Axis, Element, Event, EventContext, LayoutContext, - MutableAppContext, PaintContext, SizeConstraint, Vector2FExt, + AfterLayoutContext, Axis, Element, ElementBox, Event, EventContext, LayoutContext, + PaintContext, SizeConstraint, Vector2FExt, }; use pathfinder_geometry::vector::{vec2f, Vector2F}; -use std::any::Any; pub struct Flex { axis: Axis, - children: Vec>, - size: Option, - origin: Option, + children: Vec, } impl Flex { @@ -17,8 +16,6 @@ impl Flex { Self { axis, children: Default::default(), - size: None, - origin: None, } } @@ -30,39 +27,41 @@ impl Flex { Self::new(Axis::Vertical) } - fn child_flex<'b>(child: &dyn Element) -> Option { + fn child_flex<'b>(child: &ElementBox) -> Option { child - .parent_data() + .metadata() .and_then(|d| d.downcast_ref::()) .map(|data| data.flex) } } -impl Extend> for Flex { - fn extend>>(&mut self, children: T) { +impl Extend for Flex { + fn extend>(&mut self, children: T) { self.children.extend(children); } } impl Element for Flex { + type LayoutState = (); + type PaintState = (); + fn layout( &mut self, constraint: SizeConstraint, ctx: &mut LayoutContext, - app: &AppContext, - ) -> Vector2F { + ) -> (Vector2F, Self::LayoutState) { let mut total_flex = 0.0; let mut fixed_space = 0.0; let cross_axis = self.axis.invert(); let mut cross_axis_max: f32 = 0.0; for child in &mut self.children { - if let Some(flex) = Self::child_flex(child.as_ref()) { + if let Some(flex) = Self::child_flex(&child) { total_flex += flex; } else { let child_constraint = SizeConstraint::strict_along(cross_axis, constraint.max_along(cross_axis)); - let size = child.layout(child_constraint, ctx, app); + let size = child.layout(child_constraint, ctx); fixed_space += size.along(self.axis); cross_axis_max = cross_axis_max.max(size.along(cross_axis)); } @@ -77,7 +76,7 @@ impl Element for Flex { let mut remaining_flex = total_flex; for child in &mut self.children { let space_per_flex = remaining_space / remaining_flex; - if let Some(flex) = Self::child_flex(child.as_ref()) { + if let Some(flex) = Self::child_flex(&child) { let child_max = space_per_flex * flex; let child_constraint = match self.axis { Axis::Horizontal => SizeConstraint::new( @@ -89,7 +88,7 @@ impl Element for Flex { vec2f(constraint.max.x(), child_max), ), }; - let child_size = child.layout(child_constraint, ctx, app); + let child_size = child.layout(child_constraint, ctx); remaining_space -= child_size.along(self.axis); remaining_flex -= flex; cross_axis_max = cross_axis_max.max(child_size.along(cross_axis)); @@ -110,45 +109,55 @@ impl Element for Flex { if constraint.min.x().is_finite() { size.set_x(size.x().max(constraint.min.x())); } + if constraint.min.y().is_finite() { size.set_y(size.y().max(constraint.min.y())); } - self.size = Some(size); - size + (size, ()) } - fn after_layout(&mut self, ctx: &mut AfterLayoutContext, app: &mut MutableAppContext) { + fn after_layout( + &mut self, + _: Vector2F, + _: &mut Self::LayoutState, + ctx: &mut AfterLayoutContext, + ) { for child in &mut self.children { - child.after_layout(ctx, app); + child.after_layout(ctx); } } - fn paint(&mut self, mut origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) { - self.origin = Some(origin); - + fn paint( + &mut self, + bounds: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + ctx: &mut PaintContext, + ) -> Self::PaintState { + let mut child_origin = bounds.origin(); for child in &mut self.children { - child.paint(origin, ctx, app); + child.paint(child_origin, ctx); match self.axis { - Axis::Horizontal => origin += vec2f(child.size().unwrap().x(), 0.0), - Axis::Vertical => origin += vec2f(0.0, child.size().unwrap().y()), + Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0), + Axis::Vertical => child_origin += vec2f(0.0, child.size().y()), } } } - fn dispatch_event(&self, event: &Event, ctx: &mut EventContext, app: &AppContext) -> bool { + fn dispatch_event( + &mut self, + event: &Event, + _: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + _: &mut Self::PaintState, + ctx: &mut EventContext, + ) -> bool { let mut handled = false; - for child in &self.children { - if child.dispatch_event(event, ctx, app) { - handled = true; - } + for child in &mut self.children { + handled = child.dispatch_event(event, ctx) || handled; } handled } - - fn size(&self) -> Option { - self.size - } } struct FlexParentData { @@ -156,46 +165,62 @@ struct FlexParentData { } pub struct Expanded { - parent_data: FlexParentData, - child: Box, + metadata: FlexParentData, + child: ElementBox, } impl Expanded { - pub fn new(flex: f32, child: Box) -> Self { + pub fn new(flex: f32, child: ElementBox) -> Self { Expanded { - parent_data: FlexParentData { flex }, + metadata: FlexParentData { flex }, child, } } } impl Element for Expanded { + type LayoutState = (); + type PaintState = (); + fn layout( &mut self, constraint: SizeConstraint, ctx: &mut LayoutContext, - app: &AppContext, - ) -> Vector2F { - self.child.layout(constraint, ctx, app) + ) -> (Vector2F, Self::LayoutState) { + let size = self.child.layout(constraint, ctx); + (size, ()) } - fn after_layout(&mut self, ctx: &mut AfterLayoutContext, app: &mut MutableAppContext) { - self.child.after_layout(ctx, app); + fn after_layout( + &mut self, + _: Vector2F, + _: &mut Self::LayoutState, + ctx: &mut AfterLayoutContext, + ) { + self.child.after_layout(ctx); } - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) { - self.child.paint(origin, ctx, app); + fn paint( + &mut self, + bounds: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + ctx: &mut PaintContext, + ) -> Self::PaintState { + self.child.paint(bounds.origin(), ctx) } - fn dispatch_event(&self, event: &Event, ctx: &mut EventContext, app: &AppContext) -> bool { - self.child.dispatch_event(event, ctx, app) + fn dispatch_event( + &mut self, + event: &Event, + _: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + _: &mut Self::PaintState, + ctx: &mut EventContext, + ) -> bool { + self.child.dispatch_event(event, ctx) } - fn size(&self) -> Option { - self.child.size() - } - - fn parent_data(&self) -> Option<&dyn Any> { - Some(&self.parent_data) + fn metadata(&self) -> Option<&dyn Any> { + Some(&self.metadata) } } diff --git a/gpui/src/elements/label.rs b/gpui/src/elements/label.rs index 67945d2b5c..83ca3c7db9 100644 --- a/gpui/src/elements/label.rs +++ b/gpui/src/elements/label.rs @@ -3,8 +3,7 @@ use crate::{ fonts::{FamilyId, Properties}, geometry::vector::{vec2f, Vector2F}, text_layout::Line, - AfterLayoutContext, AppContext, Element, Event, EventContext, LayoutContext, MutableAppContext, - PaintContext, SizeConstraint, + AfterLayoutContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint, }; use std::{ops::Range, sync::Arc}; @@ -14,9 +13,11 @@ pub struct Label { font_properties: Properties, font_size: f32, highlights: Option, - layout_line: Option>, - colors: Option, ColorU)>>, - size: Option, +} + +pub struct LayoutState { + line: Arc, + colors: Vec<(Range, ColorU)>, } pub struct Highlights { @@ -33,9 +34,6 @@ impl Label { font_properties: Properties::new(), font_size, highlights: None, - layout_line: None, - colors: None, - size: None, } } @@ -55,12 +53,14 @@ impl Label { } impl Element for Label { + type LayoutState = LayoutState; + type PaintState = (); + fn layout( &mut self, constraint: SizeConstraint, ctx: &mut LayoutContext, - _: &AppContext, - ) -> Vector2F { + ) -> (Vector2F, Self::LayoutState) { let font_id = ctx .font_cache .select_font(self.family_id, &self.font_properties) @@ -109,9 +109,7 @@ impl Element for Label { colors = vec![(0..text_len, ColorU::black())]; } - self.colors = Some(colors); - - let layout_line = ctx.text_layout_cache.layout_str( + let line = ctx.text_layout_cache.layout_str( self.text.as_str(), self.font_size, styles.as_slice(), @@ -119,37 +117,33 @@ impl Element for Label { ); let size = vec2f( - layout_line - .width - .max(constraint.min.x()) - .min(constraint.max.x()), + line.width.max(constraint.min.x()).min(constraint.max.x()), ctx.font_cache.line_height(font_id, self.font_size).ceil(), ); - self.layout_line = Some(layout_line); - self.size = Some(size); - - size + (size, LayoutState { line, colors }) } - fn after_layout(&mut self, _: &mut AfterLayoutContext, _: &mut MutableAppContext) {} - - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, _: &AppContext) { - // ctx.canvas.set_fill_style(FillStyle::Color(ColorU::black())); - // self.layout_line.as_ref().unwrap().paint( - // origin, - // RectF::new(origin, self.size.unwrap()), - // self.colors.as_ref().unwrap(), - // ctx.canvas, - // ctx.font_cache, - // ); + fn after_layout(&mut self, _: Vector2F, _: &mut Self::LayoutState, _: &mut AfterLayoutContext) { } - fn size(&self) -> Option { - self.size + fn paint( + &mut self, + bounds: pathfinder_geometry::rect::RectF, + layout: &mut Self::LayoutState, + ctx: &mut PaintContext, + ) -> Self::PaintState { + layout.line.paint(bounds, layout.colors.as_slice(), ctx) } - fn dispatch_event(&self, _: &Event, _: &mut EventContext, _: &AppContext) -> bool { + fn dispatch_event( + &mut self, + _: &Event, + _: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + _: &mut Self::PaintState, + _: &mut EventContext, + ) -> bool { false } } diff --git a/gpui/src/elements/line_box.rs b/gpui/src/elements/line_box.rs index 22b6349975..0c9dbada2a 100644 --- a/gpui/src/elements/line_box.rs +++ b/gpui/src/elements/line_box.rs @@ -1,45 +1,42 @@ -use super::{AppContext, Element, MutableAppContext}; use crate::{ fonts::{FamilyId, FontId, Properties}, geometry::vector::{vec2f, Vector2F}, - AfterLayoutContext, Event, EventContext, LayoutContext, PaintContext, SizeConstraint, + AfterLayoutContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, + SizeConstraint, }; pub struct LineBox { - child: Box, + child: ElementBox, family_id: FamilyId, font_size: f32, font_properties: Properties, - font_id: Option, - size: Option, } impl LineBox { - pub fn new(family_id: FamilyId, font_size: f32, child: Box) -> Self { + pub fn new(family_id: FamilyId, font_size: f32, child: ElementBox) -> Self { Self { child, family_id, font_size, font_properties: Properties::default(), - font_id: None, - size: None, } } } impl Element for LineBox { + type LayoutState = Option; + type PaintState = (); + fn layout( &mut self, constraint: SizeConstraint, ctx: &mut LayoutContext, - app: &AppContext, - ) -> Vector2F { + ) -> (Vector2F, Self::LayoutState) { match ctx .font_cache .select_font(self.family_id, &self.font_properties) { Ok(font_id) => { - self.font_id = Some(font_id); let line_height = ctx.font_cache.bounding_box(font_id, self.font_size).y(); let child_max = vec2f( constraint.max.x(), @@ -49,36 +46,47 @@ impl Element for LineBox { let child_size = self.child.layout( SizeConstraint::new(constraint.min.min(child_max), child_max), ctx, - app, ); let size = vec2f(child_size.x(), line_height); - self.size = Some(size); - size + (size, Some(font_id)) } Err(error) => { - log::error!("can't layout LineBox: {}", error); - self.size = Some(constraint.min); - constraint.min + log::error!("can't find font for LineBox: {}", error); + (constraint.min, None) } } } - fn after_layout(&mut self, ctx: &mut AfterLayoutContext, app: &mut MutableAppContext) { - self.child.after_layout(ctx, app); + fn after_layout( + &mut self, + _: Vector2F, + _: &mut Self::LayoutState, + ctx: &mut AfterLayoutContext, + ) { + self.child.after_layout(ctx); } - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) { - if let Some(font_id) = self.font_id { - let descent = ctx.font_cache.descent(font_id, self.font_size); - self.child.paint(origin + vec2f(0.0, -descent), ctx, app); + fn paint( + &mut self, + bounds: pathfinder_geometry::rect::RectF, + font_id: &mut Option, + ctx: &mut PaintContext, + ) -> Self::PaintState { + if let Some(font_id) = font_id { + let descent = ctx.font_cache.descent(*font_id, self.font_size); + self.child + .paint(bounds.origin() + vec2f(0.0, -descent), ctx); } } - fn size(&self) -> Option { - self.size - } - - fn dispatch_event(&self, event: &Event, ctx: &mut EventContext, app: &AppContext) -> bool { - self.child.dispatch_event(event, ctx, app) + fn dispatch_event( + &mut self, + event: &Event, + _: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + _: &mut Self::PaintState, + ctx: &mut EventContext, + ) -> bool { + self.child.dispatch_event(event, ctx) } } diff --git a/gpui/src/elements/mod.rs b/gpui/src/elements/mod.rs index 19f14b8740..121fa9b6a6 100644 --- a/gpui/src/elements/mod.rs +++ b/gpui/src/elements/mod.rs @@ -6,6 +6,7 @@ mod event_handler; mod flex; mod label; mod line_box; +mod new; mod stack; mod svg; mod uniform_list; @@ -19,66 +20,33 @@ pub use event_handler::*; pub use flex::*; pub use label::*; pub use line_box::*; +pub use new::*; pub use stack::*; pub use svg::*; pub use uniform_list::*; use crate::{ - AfterLayoutContext, AppContext, Event, EventContext, LayoutContext, MutableAppContext, - PaintContext, SizeConstraint, + AfterLayoutContext, AppContext, Event, EventContext, LayoutContext, PaintContext, + SizeConstraint, }; -use pathfinder_geometry::{rect::RectF, vector::Vector2F}; -use std::any::Any; -pub trait Element { - fn layout( - &mut self, - constraint: SizeConstraint, - ctx: &mut LayoutContext, - app: &AppContext, - ) -> Vector2F; - - fn after_layout(&mut self, _: &mut AfterLayoutContext, _: &mut MutableAppContext) {} - - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext); - - fn size(&self) -> Option; - - fn parent_data(&self) -> Option<&dyn Any> { - None - } - - fn dispatch_event(&self, event: &Event, ctx: &mut EventContext, app: &AppContext) -> bool; - - fn boxed(self) -> Box - where - Self: 'static + Sized, - { - Box::new(self) - } -} - -pub trait ParentElement<'a>: Extend> + Sized { - fn add_children(&mut self, children: impl IntoIterator>) { +pub trait ParentElement<'a>: Extend + Sized { + fn add_children(&mut self, children: impl IntoIterator) { self.extend(children); } - fn add_child(&mut self, child: Box) { + fn add_child(&mut self, child: ElementBox) { self.add_children(Some(child)); } - fn with_children(mut self, children: impl IntoIterator>) -> Self { + fn with_children(mut self, children: impl IntoIterator) -> Self { self.add_children(children); self } - fn with_child(self, child: Box) -> Self { + fn with_child(self, child: ElementBox) -> Self { self.with_children(Some(child)) } } -impl<'a, T> ParentElement<'a> for T where T: Extend> {} - -pub fn try_rect(origin: Option, size: Option) -> Option { - origin.and_then(|origin| size.map(|size| RectF::new(origin, size))) -} +impl<'a, T> ParentElement<'a> for T where T: Extend {} diff --git a/gpui/src/elements/new.rs b/gpui/src/elements/new.rs new file mode 100644 index 0000000000..896c143288 --- /dev/null +++ b/gpui/src/elements/new.rs @@ -0,0 +1,191 @@ +use crate::{ + geometry::{rect::RectF, vector::Vector2F}, + AfterLayoutContext, Event, EventContext, LayoutContext, PaintContext, SizeConstraint, +}; +use core::panic; +use replace_with::replace_with_or_abort; +use std::any::Any; + +trait AnyElement { + fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F; + fn after_layout(&mut self, _: &mut AfterLayoutContext) {} + fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext); + fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool; + + fn size(&self) -> Vector2F; + fn metadata(&self) -> Option<&dyn Any>; +} + +pub trait Element { + type LayoutState; + type PaintState; + + fn layout( + &mut self, + constraint: SizeConstraint, + ctx: &mut LayoutContext, + ) -> (Vector2F, Self::LayoutState); + + fn after_layout( + &mut self, + size: Vector2F, + layout: &mut Self::LayoutState, + ctx: &mut AfterLayoutContext, + ); + + fn paint( + &mut self, + bounds: RectF, + layout: &mut Self::LayoutState, + ctx: &mut PaintContext, + ) -> Self::PaintState; + + fn dispatch_event( + &mut self, + event: &Event, + bounds: RectF, + layout: &mut Self::LayoutState, + paint: &mut Self::PaintState, + ctx: &mut EventContext, + ) -> bool; + + fn metadata(&self) -> Option<&dyn Any> { + None + } + + fn boxed(self) -> ElementBox + where + Self: 'static + Sized, + { + ElementBox(Box::new(Lifecycle::Init { element: self })) + } +} + +pub enum Lifecycle { + Init { + element: T, + }, + PostLayout { + element: T, + size: Vector2F, + layout: T::LayoutState, + }, + PostPaint { + element: T, + bounds: RectF, + layout: T::LayoutState, + paint: T::PaintState, + }, +} +pub struct ElementBox(Box); + +impl AnyElement for Lifecycle { + fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F { + let mut result = None; + replace_with_or_abort(self, |me| match me { + Lifecycle::Init { mut element } + | Lifecycle::PostLayout { mut element, .. } + | Lifecycle::PostPaint { mut element, .. } => { + let (size, layout) = element.layout(constraint, ctx); + result = Some(size); + Lifecycle::PostLayout { + element, + size, + layout, + } + } + }); + result.unwrap() + } + + fn after_layout(&mut self, ctx: &mut AfterLayoutContext) { + if let Lifecycle::PostLayout { + element, + size, + layout, + } = self + { + element.after_layout(*size, layout, ctx); + } else { + panic!("invalid element lifecycle state"); + } + } + + fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) { + replace_with_or_abort(self, |me| { + if let Lifecycle::PostLayout { + mut element, + size, + mut layout, + } = me + { + let bounds = RectF::new(origin, size); + let paint = element.paint(bounds, &mut layout, ctx); + Lifecycle::PostPaint { + element, + bounds, + layout, + paint, + } + } else { + panic!("invalid element lifecycle state"); + } + }); + } + + fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool { + if let Lifecycle::PostPaint { + element, + bounds, + layout, + paint, + } = self + { + element.dispatch_event(event, *bounds, layout, paint, ctx) + } else { + panic!("invalid element lifecycle state"); + } + } + + fn size(&self) -> Vector2F { + match self { + Lifecycle::Init { .. } => panic!("invalid element lifecycle state"), + Lifecycle::PostLayout { size, .. } => *size, + Lifecycle::PostPaint { bounds, .. } => bounds.size(), + } + } + + fn metadata(&self) -> Option<&dyn Any> { + match self { + Lifecycle::Init { element } + | Lifecycle::PostLayout { element, .. } + | Lifecycle::PostPaint { element, .. } => element.metadata(), + } + } +} + +impl ElementBox { + pub fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F { + self.0.layout(constraint, ctx) + } + + pub fn after_layout(&mut self, ctx: &mut AfterLayoutContext) { + self.0.after_layout(ctx); + } + + pub fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) { + self.0.paint(origin, ctx); + } + + pub fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool { + self.0.dispatch_event(event, ctx) + } + + pub fn size(&self) -> Vector2F { + self.0.size() + } + + pub fn metadata(&self) -> Option<&dyn Any> { + self.0.metadata() + } +} diff --git a/gpui/src/elements/stack.rs b/gpui/src/elements/stack.rs index 20f5f1e890..0d6858118d 100644 --- a/gpui/src/elements/stack.rs +++ b/gpui/src/elements/stack.rs @@ -1,65 +1,77 @@ use crate::{ - geometry::vector::Vector2F, AfterLayoutContext, AppContext, Element, Event, EventContext, - LayoutContext, MutableAppContext, PaintContext, SizeConstraint, + geometry::vector::Vector2F, AfterLayoutContext, Element, ElementBox, Event, EventContext, + LayoutContext, PaintContext, SizeConstraint, }; pub struct Stack { - children: Vec>, - size: Option, + children: Vec, } impl Stack { pub fn new() -> Self { Stack { children: Vec::new(), - size: None, } } } impl Element for Stack { + type LayoutState = (); + type PaintState = (); + fn layout( &mut self, constraint: SizeConstraint, ctx: &mut LayoutContext, - app: &AppContext, - ) -> Vector2F { + ) -> (Vector2F, Self::LayoutState) { let mut size = constraint.min; for child in &mut self.children { - size = size.max(child.layout(constraint, ctx, app)); + size = size.max(child.layout(constraint, ctx)); } - self.size = Some(size); - size + (size, ()) } - fn after_layout(&mut self, ctx: &mut AfterLayoutContext, app: &mut MutableAppContext) { + fn after_layout( + &mut self, + _: Vector2F, + _: &mut Self::LayoutState, + ctx: &mut AfterLayoutContext, + ) { for child in &mut self.children { - child.after_layout(ctx, app); + child.after_layout(ctx); } } - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) { + fn paint( + &mut self, + bounds: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + ctx: &mut PaintContext, + ) -> Self::PaintState { for child in &mut self.children { - child.paint(origin, ctx, app); + child.paint(bounds.origin(), ctx); } } - fn dispatch_event(&self, event: &Event, ctx: &mut EventContext, app: &AppContext) -> bool { - for child in self.children.iter().rev() { - if child.dispatch_event(event, ctx, app) { + fn dispatch_event( + &mut self, + event: &Event, + _: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + _: &mut Self::PaintState, + ctx: &mut EventContext, + ) -> bool { + for child in self.children.iter_mut().rev() { + if child.dispatch_event(event, ctx) { return true; } } false } - - fn size(&self) -> Option { - self.size - } } -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/gpui/src/elements/svg.rs b/gpui/src/elements/svg.rs index aab265541d..058fefd285 100644 --- a/gpui/src/elements/svg.rs +++ b/gpui/src/elements/svg.rs @@ -1,31 +1,27 @@ use crate::{ - geometry::vector::Vector2F, AfterLayoutContext, AppContext, Element, Event, EventContext, - LayoutContext, MutableAppContext, PaintContext, SizeConstraint, + geometry::vector::Vector2F, AfterLayoutContext, Element, Event, EventContext, LayoutContext, + PaintContext, SizeConstraint, }; pub struct Svg { path: String, - // tree: Option>, - size: Option, } impl Svg { pub fn new(path: String) -> Self { - Self { - path, - // tree: None, - size: None, - } + Self { path } } } impl Element for Svg { + type LayoutState = (); + type PaintState = (); + fn layout( &mut self, - constraint: SizeConstraint, - ctx: &mut LayoutContext, - _: &AppContext, - ) -> Vector2F { + _: SizeConstraint, + _: &mut LayoutContext, + ) -> (Vector2F, Self::LayoutState) { // let size; // match ctx.asset_cache.svg(&self.path) { // Ok(tree) => { @@ -52,25 +48,30 @@ impl Element for Svg { // } // }; - // self.size = Some(size); // size + todo!() } - fn after_layout(&mut self, _: &mut AfterLayoutContext, _: &mut MutableAppContext) {} - - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, _: &AppContext) { - // if let Some(tree) = self.tree.as_ref() { - // ctx.canvas - // .draw_svg(tree, RectF::new(origin, self.size.unwrap())); - // } + fn after_layout(&mut self, _: Vector2F, _: &mut Self::LayoutState, _: &mut AfterLayoutContext) { } - fn size(&self) -> Option { - self.size + fn paint( + &mut self, + _: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + _: &mut PaintContext, + ) -> Self::PaintState { } - fn dispatch_event(&self, _: &Event, _: &mut EventContext, _: &AppContext) -> bool { + fn dispatch_event( + &mut self, + _: &Event, + _: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + _: &mut Self::PaintState, + _: &mut EventContext, + ) -> bool { false } } diff --git a/gpui/src/elements/uniform_list.rs b/gpui/src/elements/uniform_list.rs index 0cddfe79e8..3cb5f4198b 100644 --- a/gpui/src/elements/uniform_list.rs +++ b/gpui/src/elements/uniform_list.rs @@ -1,10 +1,13 @@ use super::{ - try_rect, AfterLayoutContext, AppContext, Element, Event, EventContext, LayoutContext, - MutableAppContext, PaintContext, SizeConstraint, + AfterLayoutContext, AppContext, Element, Event, EventContext, LayoutContext, PaintContext, + SizeConstraint, }; -use crate::geometry::{ - rect::RectF, - vector::{vec2f, Vector2F}, +use crate::{ + geometry::{ + rect::RectF, + vector::{vec2f, Vector2F}, + }, + ElementBox, }; use parking_lot::Mutex; use std::{cmp, ops::Range, sync::Arc}; @@ -12,11 +15,6 @@ use std::{cmp, ops::Range, sync::Arc}; #[derive(Clone)] pub struct UniformListState(Arc>); -struct StateInner { - scroll_top: f32, - scroll_to: Option, -} - impl UniformListState { pub fn new() -> Self { Self(Arc::new(Mutex::new(StateInner { @@ -28,34 +26,41 @@ impl UniformListState { pub fn scroll_to(&self, item_ix: usize) { self.0.lock().scroll_to = Some(item_ix); } + + pub fn scroll_top(&self) -> f32 { + self.0.lock().scroll_top + } +} + +struct StateInner { + scroll_top: f32, + scroll_to: Option, +} + +pub struct LayoutState { + scroll_max: f32, + item_height: f32, + items: Vec, } pub struct UniformList where - F: Fn(Range, &mut Vec>, &AppContext), + F: Fn(Range, &mut Vec, &AppContext), { state: UniformListState, item_count: usize, append_items: F, - scroll_max: Option, - items: Vec>, - origin: Option, - size: Option, } impl UniformList where - F: Fn(Range, &mut Vec>, &AppContext), + F: Fn(Range, &mut Vec, &AppContext), { pub fn new(state: UniformListState, item_count: usize, build_items: F) -> Self { Self { state, item_count, append_items: build_items, - scroll_max: None, - items: Default::default(), - origin: None, - size: None, } } @@ -64,8 +69,8 @@ where position: Vector2F, delta: Vector2F, precise: bool, + scroll_max: f32, ctx: &mut EventContext, - _: &AppContext, ) -> bool { if !self.rect().unwrap().contains_point(position) { return false; @@ -76,18 +81,15 @@ where } let mut state = self.state.0.lock(); - state.scroll_top = (state.scroll_top - delta.y()) - .max(0.0) - .min(self.scroll_max.unwrap()); + state.scroll_top = (state.scroll_top - delta.y()).max(0.0).min(scroll_max); ctx.dispatch_action("uniform_list:scroll", state.scroll_top); true } - fn autoscroll(&mut self, list_height: f32, item_height: f32) { + fn autoscroll(&mut self, scroll_max: f32, list_height: f32, item_height: f32) { let mut state = self.state.0.lock(); - let scroll_max = self.item_count as f32 * item_height - list_height; if state.scroll_top > scroll_max { state.scroll_top = scroll_max; } @@ -109,20 +111,23 @@ where } fn rect(&self) -> Option { - try_rect(self.origin, self.size) + todo!() + // try_rect(self.origin, self.size) } } impl Element for UniformList where - F: Fn(Range, &mut Vec>, &AppContext), + F: Fn(Range, &mut Vec, &AppContext), { + type LayoutState = LayoutState; + type PaintState = (); + fn layout( &mut self, constraint: SizeConstraint, ctx: &mut LayoutContext, - app: &AppContext, - ) -> Vector2F { + ) -> (Vector2F, Self::LayoutState) { if constraint.max.y().is_infinite() { unimplemented!( "UniformList does not support being rendered with an unconstrained height" @@ -131,79 +136,91 @@ where let mut size = constraint.max; let mut item_constraint = SizeConstraint::new(vec2f(size.x(), 0.0), vec2f(size.x(), f32::INFINITY)); + let mut item_height = 0.; + let mut scroll_max = 0.; - self.items.clear(); - (self.append_items)(0..1, &mut self.items, app); - if let Some(first_item) = self.items.first_mut() { - let mut item_size = first_item.layout(item_constraint, ctx, app); + let mut items = Vec::new(); + (self.append_items)(0..1, &mut items, ctx.app); + if let Some(first_item) = items.first_mut() { + let mut item_size = first_item.layout(item_constraint, ctx); item_size.set_x(size.x()); item_constraint.min = item_size; item_constraint.max = item_size; + item_height = item_size.y(); - let scroll_height = self.item_count as f32 * item_size.y(); + let scroll_height = self.item_count as f32 * item_height; if scroll_height < size.y() { size.set_y(size.y().min(scroll_height).max(constraint.min.y())); } - self.autoscroll(size.y(), item_size.y()); + scroll_max = item_height * self.item_count as f32 - size.y(); + self.autoscroll(scroll_max, size.y(), item_height); - let start = cmp::min( - (self.scroll_top() / item_size.y()) as usize, - self.item_count, - ); + items.clear(); + let start = cmp::min((self.scroll_top() / item_height) as usize, self.item_count); let end = cmp::min( self.item_count, - start + (size.y() / item_size.y()).ceil() as usize + 1, + start + (size.y() / item_height).ceil() as usize + 1, ); - self.items.clear(); - (self.append_items)(start..end, &mut self.items, app); - - self.scroll_max = Some(item_size.y() * self.item_count as f32 - size.y()); - - for item in &mut self.items { - item.layout(item_constraint, ctx, app); + (self.append_items)(start..end, &mut items, ctx.app); + for item in &mut items { + item.layout(item_constraint, ctx); } } - self.size = Some(size); - size + ( + size, + LayoutState { + item_height, + scroll_max, + items, + }, + ) } - fn after_layout(&mut self, ctx: &mut AfterLayoutContext, app: &mut MutableAppContext) { - for item in &mut self.items { - item.after_layout(ctx, app); + fn after_layout( + &mut self, + _: Vector2F, + layout: &mut Self::LayoutState, + ctx: &mut AfterLayoutContext, + ) { + for item in &mut layout.items { + item.after_layout(ctx); } } - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) { - // self.origin = Some(origin); + fn paint( + &mut self, + bounds: RectF, + layout: &mut Self::LayoutState, + ctx: &mut PaintContext, + ) -> Self::PaintState { + // ctx.canvas.save(); + // let mut clip_path = Path2D::new(); + // clip_path.rect(RectF::new(origin, self.size.unwrap())); + // ctx.canvas.clip_path(clip_path, FillRule::Winding); - // if let Some(item) = self.items.first() { - // ctx.canvas.save(); - // let mut clip_path = Path2D::new(); - // clip_path.rect(RectF::new(origin, self.size.unwrap())); - // ctx.canvas.clip_path(clip_path, FillRule::Winding); + let mut item_origin = + bounds.origin() - vec2f(0.0, self.state.scroll_top() % layout.item_height); - // let item_height = item.size().unwrap().y(); - // let mut item_origin = origin - vec2f(0.0, self.state.0.lock().scroll_top % item_height); - // for item in &mut self.items { - // item.paint(item_origin, ctx, app); - // item_origin += vec2f(0.0, item_height); - // } - // ctx.canvas.restore(); - // } + for item in &mut layout.items { + item.paint(item_origin, ctx); + item_origin += vec2f(0.0, layout.item_height); + } + // ctx.canvas.restore(); } - fn size(&self) -> Option { - self.size - } - - fn dispatch_event(&self, event: &Event, ctx: &mut EventContext, app: &AppContext) -> bool { + fn dispatch_event( + &mut self, + event: &Event, + _: RectF, + layout: &mut Self::LayoutState, + _: &mut Self::PaintState, + ctx: &mut EventContext, + ) -> bool { let mut handled = false; - for item in &self.items { - if item.dispatch_event(event, ctx, app) { - handled = true; - } + for item in &mut layout.items { + handled = item.dispatch_event(event, ctx) || handled; } match event { @@ -212,7 +229,7 @@ where delta, precise, } => { - if self.scroll(*position, *delta, *precise, ctx, app) { + if self.scroll(*position, *delta, *precise, layout.scroll_max, ctx) { handled = true; } } diff --git a/gpui/src/lib.rs b/gpui/src/lib.rs index 7c91a6e76a..0aa504abae 100644 --- a/gpui/src/lib.rs +++ b/gpui/src/lib.rs @@ -11,7 +11,7 @@ pub use scene::{Border, Scene}; pub mod text_layout; pub use text_layout::TextLayoutCache; mod util; -pub use elements::Element; +pub use elements::{Element, ElementBox}; pub mod executor; pub mod keymap; pub mod platform; diff --git a/gpui/src/platform/mac/renderer.rs b/gpui/src/platform/mac/renderer.rs index 857f23fc75..ba207544db 100644 --- a/gpui/src/platform/mac/renderer.rs +++ b/gpui/src/platform/mac/renderer.rs @@ -97,7 +97,6 @@ impl Renderer { for quad_batch in layer.quads().chunks(batch_size) { for (ix, quad) in quad_batch.iter().enumerate() { let bounds = quad.bounds * scene.scale_factor(); - log::info!("render quad {:?}", quad); let shader_quad = shaders::GPUIQuad { origin: bounds.origin().to_float2(), size: bounds.size().to_float2(), diff --git a/gpui/src/platform/mac/window.rs b/gpui/src/platform/mac/window.rs index 2b489f3cd6..d41694784d 100644 --- a/gpui/src/platform/mac/window.rs +++ b/gpui/src/platform/mac/window.rs @@ -292,7 +292,6 @@ impl platform::WindowContext for WindowState { } fn present_scene(&mut self, scene: Scene) { - log::info!("present scene"); self.scene_to_render = Some(scene); unsafe { let _: () = msg_send![self.native_window.contentView(), setNeedsDisplay: YES]; @@ -421,7 +420,6 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { } extern "C" fn display_layer(this: &Object, _: Sel, _: id) { - log::info!("display layer"); unsafe { let window_state = get_window_state(this); let mut window_state = window_state.as_ref().borrow_mut(); diff --git a/gpui/src/presenter.rs b/gpui/src/presenter.rs index 016f49987f..717b4c8f31 100644 --- a/gpui/src/presenter.rs +++ b/gpui/src/presenter.rs @@ -4,14 +4,14 @@ use crate::{ fonts::FontCache, platform::Event, text_layout::TextLayoutCache, - AssetCache, Scene, + AssetCache, ElementBox, Scene, }; use pathfinder_geometry::vector::{vec2f, Vector2F}; use std::{any::Any, collections::HashMap, sync::Arc}; pub struct Presenter { window_id: usize, - rendered_views: HashMap>, + rendered_views: HashMap, parents: HashMap, font_cache: Arc, text_layout_cache: TextLayoutCache, @@ -68,13 +68,14 @@ impl Presenter { if let Some(root_view_id) = app.root_view_id(self.window_id) { self.layout(window_size, app.downgrade()); self.after_layout(app); - let mut paint_ctx = PaintContext { + let mut ctx = PaintContext { scene: &mut scene, font_cache: &self.font_cache, text_layout_cache: &self.text_layout_cache, rendered_views: &mut self.rendered_views, + app: app.downgrade(), }; - paint_ctx.paint(root_view_id, Vector2F::zero(), app.downgrade()); + ctx.paint(root_view_id, Vector2F::zero()); self.text_layout_cache.finish_frame(); } else { log::error!("could not find root_view_id for window {}", self.window_id); @@ -92,8 +93,9 @@ impl Presenter { text_layout_cache: &self.text_layout_cache, asset_cache: &self.asset_cache, view_stack: Vec::new(), + app, }; - layout_ctx.layout(root_view_id, SizeConstraint::strict(size), app); + layout_ctx.layout(root_view_id, SizeConstraint::strict(size)); } } @@ -103,35 +105,27 @@ impl Presenter { rendered_views: &mut self.rendered_views, font_cache: &self.font_cache, text_layout_cache: &self.text_layout_cache, + app, }; - ctx.after_layout(root_view_id, app); + ctx.after_layout(root_view_id); } } - pub fn responder_chain(&self, app: &AppContext) -> Option> { - app.focused_view_id(self.window_id).map(|mut view_id| { - let mut chain = vec![view_id]; - while let Some(parent_id) = self.parents.get(&view_id) { - view_id = *parent_id; - chain.push(view_id); - } - chain.reverse(); - chain - }) - } - - pub fn dispatch_event(&self, event: Event, app: &AppContext) -> Vec { - let mut event_ctx = EventContext { - rendered_views: &self.rendered_views, - actions: Vec::new(), - font_cache: &self.font_cache, - text_layout_cache: &self.text_layout_cache, - view_stack: Vec::new(), - }; + pub fn dispatch_event(&mut self, event: Event, app: &AppContext) -> Vec { if let Some(root_view_id) = app.root_view_id(self.window_id) { - event_ctx.dispatch_event_on_view(root_view_id, &event, app); + let mut ctx = EventContext { + rendered_views: &mut self.rendered_views, + actions: Vec::new(), + font_cache: &self.font_cache, + text_layout_cache: &self.text_layout_cache, + view_stack: Vec::new(), + app, + }; + ctx.dispatch_event(root_view_id, &event); + ctx.actions + } else { + Vec::new() } - event_ctx.actions } } @@ -142,22 +136,23 @@ pub struct ActionToDispatch { } pub struct LayoutContext<'a> { - rendered_views: &'a mut HashMap>, + rendered_views: &'a mut HashMap, parents: &'a mut HashMap, pub font_cache: &'a FontCache, pub text_layout_cache: &'a TextLayoutCache, pub asset_cache: &'a AssetCache, + pub app: &'a AppContext, view_stack: Vec, } impl<'a> LayoutContext<'a> { - fn layout(&mut self, view_id: usize, constraint: SizeConstraint, app: &AppContext) -> Vector2F { + fn layout(&mut self, view_id: usize, constraint: SizeConstraint) -> Vector2F { if let Some(parent_id) = self.view_stack.last() { self.parents.insert(view_id, *parent_id); } self.view_stack.push(view_id); let mut rendered_view = self.rendered_views.remove(&view_id).unwrap(); - let size = rendered_view.layout(constraint, self, app); + let size = rendered_view.layout(constraint, self); self.rendered_views.insert(view_id, rendered_view); self.view_stack.pop(); size @@ -165,55 +160,54 @@ impl<'a> LayoutContext<'a> { } pub struct AfterLayoutContext<'a> { - rendered_views: &'a mut HashMap>, + rendered_views: &'a mut HashMap, pub font_cache: &'a FontCache, pub text_layout_cache: &'a TextLayoutCache, + pub app: &'a mut MutableAppContext, } impl<'a> AfterLayoutContext<'a> { - fn after_layout(&mut self, view_id: usize, app: &mut MutableAppContext) { + fn after_layout(&mut self, view_id: usize) { if let Some(mut view) = self.rendered_views.remove(&view_id) { - view.after_layout(self, app); + view.after_layout(self); self.rendered_views.insert(view_id, view); } } } pub struct PaintContext<'a> { - rendered_views: &'a mut HashMap>, + rendered_views: &'a mut HashMap, pub scene: &'a mut Scene, pub font_cache: &'a FontCache, pub text_layout_cache: &'a TextLayoutCache, + pub app: &'a AppContext, } impl<'a> PaintContext<'a> { - fn paint(&mut self, view_id: usize, origin: Vector2F, app: &AppContext) { + fn paint(&mut self, view_id: usize, origin: Vector2F) { if let Some(mut tree) = self.rendered_views.remove(&view_id) { - tree.paint(origin, self, app); + tree.paint(origin, self); self.rendered_views.insert(view_id, tree); } } } pub struct EventContext<'a> { - rendered_views: &'a HashMap>, + rendered_views: &'a mut HashMap, actions: Vec, pub font_cache: &'a FontCache, pub text_layout_cache: &'a TextLayoutCache, + pub app: &'a AppContext, view_stack: Vec, } impl<'a> EventContext<'a> { - pub fn dispatch_event_on_view( - &mut self, - view_id: usize, - event: &Event, - app: &AppContext, - ) -> bool { - if let Some(element) = self.rendered_views.get(&view_id) { + fn dispatch_event(&mut self, view_id: usize, event: &Event) -> bool { + if let Some(mut element) = self.rendered_views.remove(&view_id) { self.view_stack.push(view_id); - let result = element.dispatch_event(event, self, app); + let result = element.dispatch_event(event, self); self.view_stack.pop(); + self.rendered_views.insert(view_id, element); result } else { false @@ -298,47 +292,54 @@ impl SizeConstraint { pub struct ChildView { view_id: usize, - size: Option, - origin: Option, } impl ChildView { pub fn new(view_id: usize) -> Self { - Self { - view_id, - size: None, - origin: None, - } + Self { view_id } } } impl Element for ChildView { + type LayoutState = (); + type PaintState = (); + fn layout( &mut self, constraint: SizeConstraint, ctx: &mut LayoutContext, - app: &AppContext, - ) -> Vector2F { - let size = ctx.layout(self.view_id, constraint, app); - self.size = Some(size); - size + ) -> (Vector2F, Self::LayoutState) { + let size = ctx.layout(self.view_id, constraint); + (size, ()) } - fn after_layout(&mut self, ctx: &mut AfterLayoutContext, app: &mut MutableAppContext) { - ctx.after_layout(self.view_id, app); + fn after_layout( + &mut self, + _: Vector2F, + _: &mut Self::LayoutState, + ctx: &mut AfterLayoutContext, + ) { + ctx.after_layout(self.view_id); } - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) { - self.origin = Some(origin); - ctx.paint(self.view_id, origin, app); + fn paint( + &mut self, + bounds: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + ctx: &mut PaintContext, + ) -> Self::PaintState { + ctx.paint(self.view_id, bounds.origin()); } - fn dispatch_event(&self, event: &Event, ctx: &mut EventContext, app: &AppContext) -> bool { - ctx.dispatch_event_on_view(self.view_id, event, app) - } - - fn size(&self) -> Option { - self.size + fn dispatch_event( + &mut self, + event: &Event, + _: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + _: &mut Self::PaintState, + ctx: &mut EventContext, + ) -> bool { + ctx.dispatch_event(self.view_id, event) } } diff --git a/gpui/src/text_layout.rs b/gpui/src/text_layout.rs index 9eef840e0b..546d6f465d 100644 --- a/gpui/src/text_layout.rs +++ b/gpui/src/text_layout.rs @@ -2,7 +2,7 @@ use crate::{ color::ColorU, fonts::{FontCache, FontId, GlyphId}, geometry::rect::RectF, - scene::Scene, + PaintContext, }; use core_foundation::{ attributed_string::CFMutableAttributedString, @@ -188,11 +188,9 @@ impl Line { pub fn paint( &self, - _origin: Vector2F, - _viewport_rect: RectF, + _bounds: RectF, _colors: &[(Range, ColorU)], - _scene: Scene, - _font_cache: &FontCache, + _ctx: &mut PaintContext, ) { // canvas.set_font_size(self.font_size); // let mut colors = colors.iter().peekable(); diff --git a/zed/src/editor/buffer_element.rs b/zed/src/editor/buffer_element.rs index 58a114813e..47995b37d0 100644 --- a/zed/src/editor/buffer_element.rs +++ b/zed/src/editor/buffer_element.rs @@ -15,31 +15,25 @@ use std::{ pub struct BufferElement { view: ViewHandle, - layout: Option, - paint: Option, } impl BufferElement { pub fn new(view: ViewHandle) -> Self { - Self { - view, - layout: None, - paint: None, - } + Self { view } } fn mouse_down( &self, position: Vector2F, cmd: bool, + layout: &mut LayoutState, + paint: &mut PaintState, ctx: &mut EventContext, - app: &AppContext, ) -> bool { - let layout = self.layout.as_ref().unwrap(); - let paint = self.paint.as_ref().unwrap(); - if paint.text_rect.contains_point(position) { - let view = self.view.as_ref(app); - let position = paint.point_for_position(view, layout, position, ctx.font_cache, app); + if paint.text_bounds.contains_point(position) { + let view = self.view.as_ref(ctx.app); + let position = + paint.point_for_position(view, layout, position, ctx.font_cache, ctx.app); ctx.dispatch_action("buffer:select", SelectAction::Begin { position, add: cmd }); true } else { @@ -47,8 +41,8 @@ impl BufferElement { } } - fn mouse_up(&self, _position: Vector2F, ctx: &mut EventContext, app: &AppContext) -> bool { - if self.view.as_ref(app).is_selecting() { + fn mouse_up(&self, _position: Vector2F, ctx: &mut EventContext) -> bool { + if self.view.as_ref(ctx.app).is_selecting() { ctx.dispatch_action("buffer:select", SelectAction::End); true } else { @@ -56,13 +50,17 @@ impl BufferElement { } } - fn mouse_dragged(&self, position: Vector2F, ctx: &mut EventContext, app: &AppContext) -> bool { - let view = self.view.as_ref(app); - let layout = self.layout.as_ref().unwrap(); - let paint = self.paint.as_ref().unwrap(); + fn mouse_dragged( + &self, + position: Vector2F, + layout: &mut LayoutState, + paint: &mut PaintState, + ctx: &mut EventContext, + ) -> bool { + let view = self.view.as_ref(ctx.app); if view.is_selecting() { - let rect = self.paint.as_ref().unwrap().text_rect; + let rect = paint.text_bounds; let mut scroll_delta = Vector2F::zero(); let vertical_margin = view.line_height(ctx.font_cache).min(rect.height() / 3.0); @@ -92,15 +90,16 @@ impl BufferElement { ctx.dispatch_action( "buffer:select", SelectAction::Update { - position: paint.point_for_position(view, layout, position, ctx.font_cache, app), + position: paint.point_for_position( + view, + layout, + position, + ctx.font_cache, + ctx.app, + ), scroll_position: (view.scroll_position() + scroll_delta).clamp( Vector2F::zero(), - self.layout.as_ref().unwrap().scroll_max( - view, - ctx.font_cache, - ctx.text_layout_cache, - app, - ), + layout.scroll_max(view, ctx.font_cache, ctx.text_layout_cache, ctx.app), ), }, ); @@ -110,8 +109,8 @@ impl BufferElement { } } - fn key_down(&self, chars: &str, ctx: &mut EventContext, app: &AppContext) -> bool { - if self.view.is_focused(app) { + fn key_down(&self, chars: &str, ctx: &mut EventContext) -> bool { + if self.view.is_focused(ctx.app) { if chars.is_empty() { false } else { @@ -132,12 +131,11 @@ impl BufferElement { position: Vector2F, delta: Vector2F, precise: bool, + layout: &mut LayoutState, + paint: &mut PaintState, ctx: &mut EventContext, - app: &AppContext, ) -> bool { - let paint = self.paint.as_ref().unwrap(); - - if !paint.rect.contains_point(position) { + if !paint.bounds.contains_point(position) { return false; } @@ -145,7 +143,7 @@ impl BufferElement { todo!("still need to handle non-precise scroll events from a mouse wheel"); } - let view = self.view.as_ref(app); + let view = self.view.as_ref(ctx.app); let font_cache = &ctx.font_cache; let layout_cache = &ctx.text_layout_cache; let max_glyph_width = view.em_width(font_cache); @@ -155,10 +153,7 @@ impl BufferElement { let y = (view.scroll_position().y() * line_height - delta.y()) / line_height; let scroll_position = vec2f(x, y).clamp( Vector2F::zero(), - self.layout - .as_ref() - .unwrap() - .scroll_max(view, font_cache, layout_cache, app), + layout.scroll_max(view, font_cache, layout_cache, ctx.app), ); ctx.dispatch_action("buffer:scroll", scroll_position); @@ -166,7 +161,7 @@ impl BufferElement { true } - fn paint_gutter(&mut self, rect: RectF, ctx: &mut PaintContext, app: &AppContext) { + fn paint_gutter(&mut self, rect: RectF, ctx: &mut PaintContext) { // if let Some(layout) = self.layout.as_ref() { // let view = self.view.as_ref(app); // let scene = &mut ctx.scene; @@ -202,7 +197,7 @@ impl BufferElement { // } } - fn paint_text(&mut self, rect: RectF, ctx: &mut PaintContext, app: &AppContext) { + fn paint_text(&mut self, rect: RectF, ctx: &mut PaintContext) { // if let Some(layout) = self.layout.as_ref() { // let scene = &mut ctx.scene; // let font_cache = &ctx.font_cache; @@ -323,12 +318,15 @@ impl BufferElement { } impl Element for BufferElement { + type LayoutState = Option; + type PaintState = Option; + fn layout( &mut self, constraint: SizeConstraint, ctx: &mut LayoutContext, - app: &AppContext, - ) -> Vector2F { + ) -> (Vector2F, Self::LayoutState) { + let app = ctx.app; let mut size = constraint.max; if size.y().is_infinite() { let view = self.view.as_ref(app); @@ -350,7 +348,7 @@ impl Element for BufferElement { match view.max_line_number_width(ctx.font_cache, ctx.text_layout_cache, app) { Err(error) => { log::error!("error computing max line number width: {}", error); - return size; + return (size, None); } Ok(width) => gutter_width = width + gutter_padding * 2.0, } @@ -368,7 +366,7 @@ impl Element for BufferElement { match view.layout_line_numbers(size.y(), ctx.font_cache, ctx.text_layout_cache, app) { Err(error) => { log::error!("error laying out line numbers: {}", error); - return size; + return (size, None); } Ok(layouts) => layouts, } @@ -385,7 +383,7 @@ impl Element for BufferElement { match view.layout_lines(start_row..end_row, font_cache, layout_cache, app) { Err(error) => { log::error!("error laying out lines: {}", error); - return size; + return (size, None); } Ok(layouts) => { for line in &layouts { @@ -398,84 +396,108 @@ impl Element for BufferElement { } }; - self.layout = Some(LayoutState { + ( size, - gutter_size, - gutter_padding, - text_size, - line_layouts, - line_number_layouts, - max_visible_line_width, - autoscroll_horizontally, - }); - - size + Some(LayoutState { + size, + gutter_size, + gutter_padding, + text_size, + line_layouts, + line_number_layouts, + max_visible_line_width, + autoscroll_horizontally, + }), + ) } - fn after_layout(&mut self, ctx: &mut AfterLayoutContext, app: &mut MutableAppContext) { - let layout = self.layout.as_ref().unwrap(); + fn after_layout( + &mut self, + _: Vector2F, + layout: &mut Option, + ctx: &mut AfterLayoutContext, + ) { + if let Some(layout) = layout { + let app = ctx.app.downgrade(); - let view = self.view.as_ref(app); - view.clamp_scroll_left( - layout - .scroll_max(view, ctx.font_cache, ctx.text_layout_cache, app.downgrade()) - .x(), - ); - - if layout.autoscroll_horizontally { - view.autoscroll_horizontally( - view.scroll_position().y() as u32, - layout.text_size.x(), - layout.scroll_width(view, ctx.font_cache, ctx.text_layout_cache, app.downgrade()), - view.em_width(ctx.font_cache), - &layout.line_layouts, - app.downgrade(), + let view = self.view.as_ref(app); + view.clamp_scroll_left( + layout + .scroll_max(view, ctx.font_cache, ctx.text_layout_cache, app) + .x(), ); + + if layout.autoscroll_horizontally { + view.autoscroll_horizontally( + view.scroll_position().y() as u32, + layout.text_size.x(), + layout.scroll_width(view, ctx.font_cache, ctx.text_layout_cache, app), + view.em_width(ctx.font_cache), + &layout.line_layouts, + app, + ); + } } } - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) { - let rect; - let gutter_rect; - let text_rect; - { - let layout = self.layout.as_ref().unwrap(); - rect = RectF::new(origin, layout.size); - gutter_rect = RectF::new(origin, layout.gutter_size); - text_rect = RectF::new( - origin + vec2f(layout.gutter_size.x(), 0.0), + fn paint( + &mut self, + bounds: RectF, + layout: &mut Self::LayoutState, + ctx: &mut PaintContext, + ) -> Self::PaintState { + if let Some(layout) = layout { + let gutter_bounds = RectF::new(bounds.origin(), layout.gutter_size); + let text_bounds = RectF::new( + bounds.origin() + vec2f(layout.gutter_size.x(), 0.0), layout.text_size, ); - } - if self.view.as_ref(app).is_gutter_visible() { - self.paint_gutter(gutter_rect, ctx, app); - } - self.paint_text(text_rect, ctx, app); + if self.view.as_ref(ctx.app).is_gutter_visible() { + self.paint_gutter(gutter_bounds, ctx); + } + self.paint_text(text_bounds, ctx); - self.paint = Some(PaintState { rect, text_rect }); - } - - fn dispatch_event(&self, event: &Event, ctx: &mut EventContext, app: &AppContext) -> bool { - match event { - Event::LeftMouseDown { position, cmd } => self.mouse_down(*position, *cmd, ctx, app), - Event::LeftMouseUp { position } => self.mouse_up(*position, ctx, app), - Event::LeftMouseDragged { position } => self.mouse_dragged(*position, ctx, app), - Event::ScrollWheel { - position, - delta, - precise, - } => self.scroll(*position, *delta, *precise, ctx, app), - Event::KeyDown { chars, .. } => self.key_down(chars, ctx, app), + Some(PaintState { + bounds, + text_bounds, + }) + } else { + None } } - fn size(&self) -> Option { - self.layout.as_ref().map(|layout| layout.size) + fn dispatch_event( + &mut self, + event: &Event, + _: RectF, + layout: &mut Self::LayoutState, + paint: &mut Self::PaintState, + ctx: &mut EventContext, + ) -> bool { + if let (Some(layout), Some(paint)) = (layout, paint) { + match event { + Event::LeftMouseDown { position, cmd } => { + self.mouse_down(*position, *cmd, layout, paint, ctx) + } + Event::LeftMouseUp { position } => self.mouse_up(*position, ctx), + Event::LeftMouseDragged { position } => { + self.mouse_dragged(*position, layout, paint, ctx) + } + Event::ScrollWheel { + position, + delta, + precise, + } => self.scroll(*position, *delta, *precise, layout, paint, ctx), + Event::KeyDown { chars, .. } => self.key_down(chars, ctx), + } + } else { + false + } } } -struct LayoutState { +pub struct LayoutState { size: Vector2F, gutter_size: Vector2F, gutter_padding: f32, @@ -518,9 +540,9 @@ impl LayoutState { } } -struct PaintState { - rect: RectF, - text_rect: RectF, +pub struct PaintState { + bounds: RectF, + text_bounds: RectF, } impl PaintState { @@ -533,7 +555,7 @@ impl PaintState { app: &AppContext, ) -> DisplayPoint { let scroll_position = view.scroll_position(); - let position = position - self.text_rect.origin(); + let position = position - self.text_bounds.origin(); let y = position.y().max(0.0).min(layout.size.y()); let row = ((y / view.line_height(font_cache)) + scroll_position.y()) as u32; let row = cmp::min(row, view.max_point(app).row()); diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs index 3e9bee9808..bdd673693e 100644 --- a/zed/src/editor/buffer_view.rs +++ b/zed/src/editor/buffer_view.rs @@ -8,7 +8,8 @@ use easy_parallel::Parallel; use gpui::{ fonts::{FontCache, Properties as FontProperties}, keymap::Binding, - text_layout, App, AppContext, Element, Entity, ModelHandle, View, ViewContext, WeakViewHandle, + text_layout, App, AppContext, Element, ElementBox, Entity, ModelHandle, View, ViewContext, + WeakViewHandle, }; use gpui::{geometry::vector::Vector2F, TextLayoutCache}; use parking_lot::Mutex; @@ -892,6 +893,7 @@ impl BufferView { font_cache.scale_metric(bounds.width(), font_id, settings.buffer_font_size) } + // TODO: Can we make this not return a result? pub fn max_line_number_width( &self, font_cache: &FontCache, @@ -1140,7 +1142,7 @@ impl Entity for BufferView { } impl View for BufferView { - fn render<'a>(&self, app: &AppContext) -> Box { + fn render<'a>(&self, app: &AppContext) -> ElementBox { BufferElement::new(self.handle.upgrade(app).unwrap()).boxed() } diff --git a/zed/src/file_finder.rs b/zed/src/file_finder.rs index e75a2ba0ff..c121b2cc2e 100644 --- a/zed/src/file_finder.rs +++ b/zed/src/file_finder.rs @@ -57,7 +57,7 @@ impl View for FileFinder { "FileFinder" } - fn render(&self, _: &AppContext) -> Box { + fn render(&self, _: &AppContext) -> ElementBox { Align::new( ConstrainedBox::new( Container::new( @@ -98,7 +98,7 @@ impl View for FileFinder { } impl FileFinder { - fn render_matches(&self) -> Box { + fn render_matches(&self) -> ElementBox { if self.matches.is_empty() { let settings = smol::block_on(self.settings.read()); return Container::new( @@ -140,7 +140,7 @@ impl FileFinder { path_match: &PathMatch, index: usize, app: &AppContext, - ) -> Option> { + ) -> Option { let tree_id = path_match.tree_id; let entry_id = path_match.entry_id; @@ -227,7 +227,7 @@ impl FileFinder { } EventHandler::new(container.boxed()) - .on_mouse_down(move |ctx, _| { + .on_mouse_down(move |ctx| { ctx.dispatch_action("file_finder:select", (tree_id, entry_id)); true }) diff --git a/zed/src/workspace/pane.rs b/zed/src/workspace/pane.rs index 5d991cd15d..671d083926 100644 --- a/zed/src/workspace/pane.rs +++ b/zed/src/workspace/pane.rs @@ -173,7 +173,7 @@ impl Pane { ctx.emit(Event::Split(direction)); } - fn render_tabs<'a>(&self, app: &AppContext) -> Box { + fn render_tabs<'a>(&self, app: &AppContext) -> ElementBox { let settings = smol::block_on(self.settings.read()); let border_color = ColorU::new(0xdb, 0xdb, 0xdc, 0xff); @@ -209,7 +209,7 @@ impl Pane { 1.0, ConstrainedBox::new( EventHandler::new(container.boxed()) - .on_mouse_down(move |ctx, _| { + .on_mouse_down(move |ctx| { ctx.dispatch_action("pane:activate_item", ix); true }) @@ -253,7 +253,7 @@ impl View for Pane { "Pane" } - fn render<'a>(&self, app: &AppContext) -> Box { + fn render<'a>(&self, app: &AppContext) -> ElementBox { if let Some(active_item) = self.active_item() { Flex::column() .with_child(self.render_tabs(app)) diff --git a/zed/src/workspace/pane_group.rs b/zed/src/workspace/pane_group.rs index b69c9046ef..46a00b3f2a 100644 --- a/zed/src/workspace/pane_group.rs +++ b/zed/src/workspace/pane_group.rs @@ -48,7 +48,7 @@ impl PaneGroup { } } - pub fn render<'a>(&self) -> Box { + pub fn render<'a>(&self) -> ElementBox { self.root.render() } } @@ -77,7 +77,7 @@ impl Member { Member::Axis(PaneAxis { axis, members }) } - pub fn render<'a>(&self) -> Box { + pub fn render<'a>(&self) -> ElementBox { match self { Member::Pane(view_id) => ChildView::new(*view_id).boxed(), Member::Axis(axis) => axis.render(), @@ -168,7 +168,7 @@ impl PaneAxis { } } - fn render<'a>(&self) -> Box { + fn render<'a>(&self) -> ElementBox { let last_member_ix = self.members.len() - 1; Flex::new(self.axis) .with_children(self.members.iter().enumerate().map(|(ix, member)| { diff --git a/zed/src/workspace/workspace_view.rs b/zed/src/workspace/workspace_view.rs index 8445f4eb7a..12c73c14f7 100644 --- a/zed/src/workspace/workspace_view.rs +++ b/zed/src/workspace/workspace_view.rs @@ -141,7 +141,6 @@ impl WorkspaceView { ctx.focus(&modal); self.modal = Some(modal.into()); } - log::info!("toggle modal notify"); ctx.notify(); } @@ -304,7 +303,7 @@ impl View for WorkspaceView { "Workspace" } - fn render(&self, _: &AppContext) -> Box { + fn render(&self, _: &AppContext) -> ElementBox { Container::new( // self.center.render(bump) Stack::new()