Start on Scene

Nathan Sobo created

Change summary

gpui/src/elements/container.rs  | 184 +---------------------------------
gpui/src/elements/empty.rs      |   2 
gpui/src/lib.rs                 |   2 
gpui/src/presenter.rs           |  41 +++----
gpui/src/scene.rs               | 122 +++++++++++++++++++++++
zed/src/main.rs                 |   2 
zed/src/workspace/pane.rs       |   2 
zed/src/workspace/pane_group.rs |   2 
8 files changed, 154 insertions(+), 203 deletions(-)

Detailed changes

gpui/src/elements/container.rs 🔗

@@ -1,6 +1,9 @@
+use pathfinder_geometry::rect::RectF;
+
 use crate::{
     color::ColorU,
     geometry::vector::{vec2f, Vector2F},
+    scene::{Border, Quad},
     AfterLayoutContext, AppContext, Element, Event, EventContext, LayoutContext, MutableAppContext,
     PaintContext, SizeConstraint,
 };
@@ -141,110 +144,13 @@ impl Element for Container {
     }
 
     fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) {
-        // self.origin = Some(origin);
-
-        // let canvas = &mut ctx.canvas;
-        // let size = self.size.unwrap() - self.margin_size()
-        //     + vec2f(self.overdraw.right, self.overdraw.bottom);
-        // let origin = origin + vec2f(self.margin.left, self.margin.top)
-        //     - vec2f(self.overdraw.left, self.overdraw.top);
-        // let rect = RectF::new(origin, size);
-
-        // let mut path = Path2D::new();
-        // if self.corner_radius > 0.0 {
-        //     path.move_to(rect.upper_right() - vec2f(self.corner_radius, 0.0));
-        //     path.arc_to(
-        //         rect.upper_right(),
-        //         rect.upper_right() + vec2f(0.0, self.corner_radius),
-        //         self.corner_radius,
-        //     );
-        //     path.line_to(rect.lower_right() - vec2f(0.0, self.corner_radius));
-        //     path.arc_to(
-        //         rect.lower_right(),
-        //         rect.lower_right() - vec2f(self.corner_radius, 0.0),
-        //         self.corner_radius,
-        //     );
-        //     path.line_to(rect.lower_left() + vec2f(self.corner_radius, 0.0));
-        //     path.arc_to(
-        //         rect.lower_left(),
-        //         rect.lower_left() - vec2f(0.0, self.corner_radius),
-        //         self.corner_radius,
-        //     );
-        //     path.line_to(origin + vec2f(0.0, self.corner_radius));
-        //     path.arc_to(
-        //         origin,
-        //         origin + vec2f(self.corner_radius, 0.0),
-        //         self.corner_radius,
-        //     );
-        //     path.close_path();
-        // } else {
-        //     path.rect(rect);
-        // }
-
-        // canvas.save();
-        // if let Some(shadow) = self.shadow.as_ref() {
-        //     canvas.set_shadow_offset(shadow.offset);
-        //     canvas.set_shadow_blur(shadow.blur);
-        //     canvas.set_shadow_color(shadow.color);
-        // }
-
-        // if let Some(background_color) = self.background_color {
-        //     canvas.set_fill_style(FillStyle::Color(background_color));
-        //     canvas.fill_path(path.clone(), FillRule::Winding);
-        // }
-
-        // canvas.set_line_width(self.border.width);
-        // canvas.set_stroke_style(FillStyle::Color(self.border.color));
-
-        // let border_rect = rect.contract(self.border.width / 2.0);
-
-        // // For now, we ignore the corner radius unless we draw a border on all sides.
-        // // This could be improved.
-        // if self.border.all_sides() {
-        //     let mut path = Path2D::new();
-        //     path.rect(border_rect);
-        //     canvas.stroke_path(path);
-        // } else {
-        //     canvas.set_line_cap(LineCap::Square);
-
-        //     if self.border.top {
-        //         let mut path = Path2D::new();
-        //         path.move_to(border_rect.origin());
-        //         path.line_to(border_rect.upper_right());
-        //         canvas.stroke_path(path);
-        //     }
-
-        //     if self.border.left {
-        //         let mut path = Path2D::new();
-        //         path.move_to(border_rect.origin());
-        //         path.line_to(border_rect.lower_left());
-        //         canvas.stroke_path(path);
-        //     }
-
-        //     if self.border.bottom {
-        //         let mut path = Path2D::new();
-        //         path.move_to(border_rect.lower_left());
-        //         path.line_to(border_rect.lower_right());
-        //         canvas.stroke_path(path);
-        //     }
-
-        //     if self.border.right {
-        //         let mut path = Path2D::new();
-        //         path.move_to(border_rect.upper_right());
-        //         path.line_to(border_rect.lower_right());
-        //         canvas.stroke_path(path);
-        //     }
-        // }
-        // canvas.restore();
-
-        // let mut child_origin = origin + vec2f(self.padding.left, self.padding.top);
-        // if self.border.left {
-        //     child_origin.set_x(child_origin.x() + self.border.width);
-        // }
-        // if self.border.top {
-        //     child_origin.set_y(child_origin.y() + self.border.width);
-        // }
-        // self.child.paint(child_origin, ctx, app);
+        ctx.scene.push_quad(Quad {
+            bounds: RectF::new(origin, self.size.unwrap()),
+            background: self.background_color,
+            border: self.border,
+            corder_radius: self.corner_radius,
+        });
+        self.child.paint(origin, ctx, app);
     }
 
     fn dispatch_event(&self, event: &Event, ctx: &mut EventContext, app: &AppContext) -> bool {
@@ -280,76 +186,6 @@ pub struct Overdraw {
     right: f32,
 }
 
-#[derive(Default)]
-pub struct Border {
-    width: f32,
-    color: ColorU,
-    pub top: bool,
-    pub left: bool,
-    pub bottom: bool,
-    pub right: bool,
-}
-
-impl Border {
-    pub fn new(width: f32, color: impl Into<ColorU>) -> Self {
-        Self {
-            width,
-            color: color.into(),
-            top: false,
-            left: false,
-            bottom: false,
-            right: false,
-        }
-    }
-
-    pub fn all(width: f32, color: impl Into<ColorU>) -> Self {
-        Self {
-            width,
-            color: color.into(),
-            top: true,
-            left: true,
-            bottom: true,
-            right: true,
-        }
-    }
-
-    pub fn top(width: f32, color: impl Into<ColorU>) -> Self {
-        let mut border = Self::new(width, color);
-        border.top = true;
-        border
-    }
-
-    pub fn left(width: f32, color: impl Into<ColorU>) -> Self {
-        let mut border = Self::new(width, color);
-        border.left = true;
-        border
-    }
-
-    pub fn bottom(width: f32, color: impl Into<ColorU>) -> Self {
-        let mut border = Self::new(width, color);
-        border.bottom = true;
-        border
-    }
-
-    pub fn right(width: f32, color: impl Into<ColorU>) -> Self {
-        let mut border = Self::new(width, color);
-        border.right = true;
-        border
-    }
-
-    pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
-        self.top = top;
-        self.left = left;
-        self.bottom = bottom;
-        self.right = right;
-        self
-    }
-
-    fn all_sides(&self) -> bool {
-        self.top && self.left && self.bottom && self.right
-    }
-}
-
 #[derive(Default)]
 pub struct Shadow {
     offset: Vector2F,

gpui/src/elements/empty.rs 🔗

@@ -25,7 +25,7 @@ impl Element for Empty {
         _: &mut LayoutContext,
         _: &AppContext,
     ) -> Vector2F {
-        self.size = Some(constraint.min);
+        self.size = Some(constraint.max);
         constraint.max
     }
 

gpui/src/lib.rs 🔗

@@ -7,7 +7,7 @@ pub mod fonts;
 pub use fonts::FontCache;
 mod presenter;
 mod scene;
-pub use scene::Scene;
+pub use scene::{Border, Scene};
 pub mod text_layout;
 pub use text_layout::TextLayoutCache;
 mod util;

gpui/src/presenter.rs 🔗

@@ -52,10 +52,23 @@ impl Presenter {
         scale_factor: f32,
         app: &mut MutableAppContext,
     ) -> Scene {
-        self.layout(window_size, app.downgrade());
-        self.after_layout(app);
-        let scene = self.paint(window_size, scale_factor, app.downgrade());
-        self.text_layout_cache.finish_frame();
+        let mut scene = Scene::new(scale_factor);
+
+        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 {
+                scene: &mut scene,
+                font_cache: &self.font_cache,
+                text_layout_cache: &self.text_layout_cache,
+                rendered_views: &mut self.rendered_views,
+            };
+            paint_ctx.paint(root_view_id, Vector2F::zero(), app.downgrade());
+            self.text_layout_cache.finish_frame();
+        } else {
+            log::error!("could not find root_view_id for window {}", self.window_id);
+        }
+
         scene
     }
 
@@ -84,24 +97,6 @@ impl Presenter {
         }
     }
 
-    fn paint(&mut self, _size: Vector2F, _scale_factor: f32, _app: &AppContext) -> Scene {
-        // let mut canvas = Canvas::new(size * scale_factor).get_context_2d(self.font_context.clone());
-        // canvas.scale(scale_factor);
-
-        // if let Some(root_view_id) = app.root_view_id(self.window_id) {
-        //     let mut paint_ctx = PaintContext {
-        //         canvas: &mut canvas,
-        //         font_cache: &self.font_cache,
-        //         text_layout_cache: &self.text_layout_cache,
-        //         rendered_views: &mut self.rendered_views,
-        //     };
-        //     paint_ctx.paint(root_view_id, Vector2F::zero(), app);
-        // }
-
-        // canvas.into_canvas().into_scene()
-        Scene {}
-    }
-
     pub fn responder_chain(&self, app: &AppContext) -> Option<Vec<usize>> {
         app.focused_view_id(self.window_id).map(|mut view_id| {
             let mut chain = vec![view_id];
@@ -173,7 +168,7 @@ impl<'a> AfterLayoutContext<'a> {
 
 pub struct PaintContext<'a> {
     rendered_views: &'a mut HashMap<usize, Box<dyn Element>>,
-    // pub canvas: &'a mut CanvasRenderingContext2D,
+    pub scene: &'a mut Scene,
     pub font_cache: &'a FontCache,
     pub text_layout_cache: &'a TextLayoutCache,
 }

gpui/src/scene.rs 🔗

@@ -1 +1,121 @@
-pub struct Scene;
+use crate::{color::ColorU, geometry::rect::RectF};
+pub struct Scene {
+    scale_factor: f32,
+    layers: Vec<Layer>,
+    active_layer_stack: Vec<usize>,
+}
+
+#[derive(Default)]
+struct Layer {
+    clip_bounds: Option<RectF>,
+    quads: Vec<Quad>,
+}
+
+#[derive(Default)]
+pub struct Quad {
+    pub bounds: RectF,
+    pub background: Option<ColorU>,
+    pub border: Border,
+    pub corder_radius: f32,
+}
+
+#[derive(Clone, Copy, Default)]
+pub struct Border {
+    pub width: f32,
+    pub color: Option<ColorU>,
+    pub top: bool,
+    pub right: bool,
+    pub bottom: bool,
+    pub left: bool,
+}
+
+impl Scene {
+    pub fn new(scale_factor: f32) -> Self {
+        Scene {
+            scale_factor,
+            layers: vec![Layer::default()],
+            active_layer_stack: vec![0],
+        }
+    }
+
+    pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {}
+
+    pub fn pop_layer(&mut self) {
+        assert!(self.active_layer_stack.len() > 1);
+        self.active_layer_stack.pop();
+    }
+
+    pub fn push_quad(&mut self, quad: Quad) {
+        self.active_layer().push_quad(quad)
+    }
+
+    fn active_layer(&mut self) -> &mut Layer {
+        &mut self.layers[*self.active_layer_stack.last().unwrap()]
+    }
+}
+
+impl Layer {
+    fn push_quad(&mut self, quad: Quad) {
+        self.quads.push(quad);
+    }
+}
+
+impl Border {
+    pub fn new(width: f32, color: impl Into<ColorU>) -> Self {
+        Self {
+            width,
+            color: Some(color.into()),
+            top: false,
+            left: false,
+            bottom: false,
+            right: false,
+        }
+    }
+
+    pub fn all(width: f32, color: impl Into<ColorU>) -> Self {
+        Self {
+            width,
+            color: Some(color.into()),
+            top: true,
+            left: true,
+            bottom: true,
+            right: true,
+        }
+    }
+
+    pub fn top(width: f32, color: impl Into<ColorU>) -> Self {
+        let mut border = Self::new(width, color);
+        border.top = true;
+        border
+    }
+
+    pub fn left(width: f32, color: impl Into<ColorU>) -> Self {
+        let mut border = Self::new(width, color);
+        border.left = true;
+        border
+    }
+
+    pub fn bottom(width: f32, color: impl Into<ColorU>) -> Self {
+        let mut border = Self::new(width, color);
+        border.bottom = true;
+        border
+    }
+
+    pub fn right(width: f32, color: impl Into<ColorU>) -> Self {
+        let mut border = Self::new(width, color);
+        border.right = true;
+        border
+    }
+
+    pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
+        self.top = top;
+        self.left = left;
+        self.bottom = bottom;
+        self.right = right;
+        self
+    }
+
+    fn all_sides(&self) -> bool {
+        self.top && self.left && self.bottom && self.right
+    }
+}

zed/src/main.rs 🔗

@@ -2,7 +2,7 @@ use fs::OpenOptions;
 use gpui::platform::{current as platform, Runner as _};
 use log::LevelFilter;
 use simplelog::SimpleLogger;
-use std::{fs, mem, path::PathBuf};
+use std::{fs, path::PathBuf};
 use zed::{
     assets, editor, settings,
     workspace::{self, OpenParams},

zed/src/workspace/pane.rs 🔗

@@ -1,7 +1,7 @@
 use super::{ItemViewHandle, SplitDirection};
 use crate::{settings::Settings, watch};
 use gpui::{
-    color::ColorU, elements::*, keymap::Binding, App, AppContext, ChildView, Entity, View,
+    color::ColorU, elements::*, keymap::Binding, App, AppContext, Border, ChildView, Entity, View,
     ViewContext,
 };
 use std::cmp;

zed/src/workspace/pane_group.rs 🔗

@@ -2,7 +2,7 @@ use anyhow::{anyhow, Result};
 use gpui::{
     color::{rgbu, ColorU},
     elements::*,
-    Axis, ChildView,
+    Axis, Border, ChildView,
 };
 
 #[derive(Clone, Debug, Eq, PartialEq)]