diff --git a/crates/gpui/examples/painting.rs b/crates/gpui/examples/painting.rs index bca9256bc5..22a3ad070f 100644 --- a/crates/gpui/examples/painting.rs +++ b/crates/gpui/examples/painting.rs @@ -27,10 +27,15 @@ impl PaintingViewer { // draw a lightening bolt ⚡ let mut builder = PathBuilder::fill(); - builder.move_to(point(px(150.), px(200.))); - builder.line_to(point(px(200.), px(125.))); - builder.line_to(point(px(200.), px(175.))); - builder.line_to(point(px(250.), px(100.))); + builder.add_polygon( + &[ + point(px(150.), px(200.)), + point(px(200.), px(125.)), + point(px(200.), px(175.)), + point(px(250.), px(100.)), + ], + false, + ); let path = builder.build().unwrap(); lines.push((path, rgb(0x1d4ed8).into())); @@ -58,6 +63,7 @@ impl PaintingViewer { .color_space(ColorSpace::Oklab), )); + // draw linear gradient let square_bounds = Bounds { origin: point(px(450.), px(100.)), size: size(px(200.), px(80.)), @@ -87,6 +93,47 @@ impl PaintingViewer { ), )); + // draw a pie chart + let center = point(px(96.), px(96.)); + let pie_center = point(px(775.), px(155.)); + let segments = [ + ( + point(px(871.), px(155.)), + point(px(747.), px(63.)), + rgb(0x1374e9), + ), + ( + point(px(747.), px(63.)), + point(px(679.), px(163.)), + rgb(0xe13527), + ), + ( + point(px(679.), px(163.)), + point(px(754.), px(249.)), + rgb(0x0751ce), + ), + ( + point(px(754.), px(249.)), + point(px(854.), px(210.)), + rgb(0x209742), + ), + ( + point(px(854.), px(210.)), + point(px(871.), px(155.)), + rgb(0xfbc10a), + ), + ]; + + for (start, end, color) in segments { + let mut builder = PathBuilder::fill(); + builder.move_to(start); + builder.arc_to(center, px(0.), false, false, end); + builder.line_to(pie_center); + builder.close(); + let path = builder.build().unwrap(); + lines.push((path, color.into())); + } + // draw a wave let options = StrokeOptions::default() .with_line_width(1.) diff --git a/crates/gpui/src/path_builder.rs b/crates/gpui/src/path_builder.rs index 982b858676..bf8d2d65bb 100644 --- a/crates/gpui/src/path_builder.rs +++ b/crates/gpui/src/path_builder.rs @@ -1,6 +1,9 @@ use anyhow::Error; -use etagere::euclid::Vector2D; +use etagere::euclid::{Point2D, Vector2D}; use lyon::geom::Angle; +use lyon::math::{Vector, vector}; +use lyon::path::traits::SvgPathBuilder; +use lyon::path::{ArcFlags, Polygon}; use lyon::tessellation::{ BuffersBuilder, FillTessellator, FillVertex, StrokeTessellator, StrokeVertex, VertexBuffers, }; @@ -56,6 +59,18 @@ impl From> for lyon::math::Point { } } +impl From> for Vector { + fn from(p: Point) -> Self { + vector(p.x.0, p.y.0) + } +} + +impl From> for Point2D { + fn from(p: Point) -> Self { + Point2D::new(p.x.0, p.y.0) + } +} + impl Default for PathBuilder { fn default() -> Self { Self { @@ -116,6 +131,49 @@ impl PathBuilder { .cubic_bezier_to(control_a.into(), control_b.into(), to.into()); } + /// Adds an elliptical arc. + pub fn arc_to( + &mut self, + radii: Point, + x_rotation: Pixels, + large_arc: bool, + sweep: bool, + to: Point, + ) { + self.raw.arc_to( + radii.into(), + Angle::degrees(x_rotation.into()), + ArcFlags { large_arc, sweep }, + to.into(), + ); + } + + /// Equivalent to `arc_to` in relative coordinates. + pub fn relative_arc_to( + &mut self, + radii: Point, + x_rotation: Pixels, + large_arc: bool, + sweep: bool, + to: Point, + ) { + self.raw.relative_arc_to( + radii.into(), + Angle::degrees(x_rotation.into()), + ArcFlags { large_arc, sweep }, + to.into(), + ); + } + + /// Adds a polygon. + pub fn add_polygon(&mut self, points: &[Point], closed: bool) { + let points = points.iter().copied().map(|p| p.into()).collect::>(); + self.raw.add_polygon(Polygon { + points: points.as_ref(), + closed, + }); + } + /// Close the current sub-path. #[inline] pub fn close(&mut self) {