summaryrefslogtreecommitdiff
path: root/library/src/visualize
diff options
context:
space:
mode:
Diffstat (limited to 'library/src/visualize')
-rw-r--r--library/src/visualize/image.rs100
-rw-r--r--library/src/visualize/line.rs34
-rw-r--r--library/src/visualize/shape.rs331
3 files changed, 262 insertions, 203 deletions
diff --git a/library/src/visualize/image.rs b/library/src/visualize/image.rs
index 5e3c7f83..fa5b70ad 100644
--- a/library/src/visualize/image.rs
+++ b/library/src/visualize/image.rs
@@ -1,10 +1,10 @@
use std::ffi::OsStr;
+use std::path::Path;
use typst::image::{Image, ImageFormat, RasterFormat, VectorFormat};
use crate::prelude::*;
-/// # Image
/// A raster or vector graphic.
///
/// Supported formats are PNG, JPEG, GIF and SVG.
@@ -18,62 +18,52 @@ use crate::prelude::*;
/// ]
/// ```
///
-/// ## Parameters
-/// - path: `EcoString` (positional, required)
-/// Path to an image file.
-///
-/// - width: `Rel<Length>` (named)
-/// The width of the image.
-///
-/// - height: `Rel<Length>` (named)
-/// The height of the image.
-///
-/// ## Category
-/// visualize
-#[func]
-#[capable(Layout)]
-#[derive(Debug, Hash)]
+/// Display: Image
+/// Category: visualize
+#[node(Construct, Layout)]
pub struct ImageNode {
- pub image: Image,
+ /// Path to an image file.
+ #[positional]
+ #[required]
+ pub path: EcoString,
+
+ /// The width of the image.
+ #[named]
+ #[default]
pub width: Smart<Rel<Length>>,
+
+ /// The height of the image.
+ #[named]
+ #[default]
pub height: Smart<Rel<Length>>,
-}
-#[node]
-impl ImageNode {
/// How the image should adjust itself to a given area.
- pub const FIT: ImageFit = ImageFit::Cover;
+ #[settable]
+ #[default(ImageFit::Cover)]
+ pub fit: ImageFit,
+}
+impl Construct for ImageNode {
fn construct(vm: &Vm, args: &mut Args) -> SourceResult<Content> {
let Spanned { v: path, span } =
args.expect::<Spanned<EcoString>>("path to image file")?;
-
- let full = vm.locate(&path).at(span)?;
- let buffer = vm.world().file(&full).at(span)?;
- let ext = full.extension().and_then(OsStr::to_str).unwrap_or_default();
- let format = match ext.to_lowercase().as_str() {
- "png" => ImageFormat::Raster(RasterFormat::Png),
- "jpg" | "jpeg" => ImageFormat::Raster(RasterFormat::Jpg),
- "gif" => ImageFormat::Raster(RasterFormat::Gif),
- "svg" | "svgz" => ImageFormat::Vector(VectorFormat::Svg),
- _ => bail!(span, "unknown image format"),
- };
-
- let image = Image::new(buffer, format).at(span)?;
- let width = args.named("width")?.unwrap_or_default();
- let height = args.named("height")?.unwrap_or_default();
- Ok(ImageNode { image, width, height }.pack())
+ let path: EcoString = vm.locate(&path).at(span)?.to_string_lossy().into();
+ let _ = load(vm.world(), &path).at(span)?;
+ let width = args.named::<Smart<Rel<Length>>>("width")?.unwrap_or_default();
+ let height = args.named::<Smart<Rel<Length>>>("height")?.unwrap_or_default();
+ Ok(ImageNode::new(path).with_width(width).with_height(height).pack())
}
}
impl Layout for ImageNode {
fn layout(
&self,
- _: &mut Vt,
+ vt: &mut Vt,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
- let sizing = Axes::new(self.width, self.height);
+ let image = load(vt.world(), &self.path()).unwrap();
+ let sizing = Axes::new(self.width(), self.height());
let region = sizing
.zip(regions.base())
.map(|(s, r)| s.map(|v| v.resolve(styles).relative_to(r)))
@@ -83,8 +73,8 @@ impl Layout for ImageNode {
let region_ratio = region.x / region.y;
// Find out whether the image is wider or taller than the target size.
- let pxw = self.image.width() as f64;
- let pxh = self.image.height() as f64;
+ let pxw = image.width() as f64;
+ let pxh = image.height() as f64;
let px_ratio = pxw / pxh;
let wide = px_ratio > region_ratio;
@@ -116,7 +106,7 @@ impl Layout for ImageNode {
// the frame to the target size, center aligning the image in the
// process.
let mut frame = Frame::new(fitted);
- frame.push(Point::zero(), Element::Image(self.image.clone(), fitted));
+ frame.push(Point::zero(), Element::Image(image, fitted));
frame.resize(target, Align::CENTER_HORIZON);
// Create a clipping group if only part of the image should be visible.
@@ -142,7 +132,7 @@ pub enum ImageFit {
Stretch,
}
-castable! {
+cast_from_value! {
ImageFit,
/// The image should completely cover the area. This is the default.
"cover" => Self::Cover,
@@ -152,3 +142,27 @@ castable! {
/// this means that the image will be distorted.
"stretch" => Self::Stretch,
}
+
+cast_to_value! {
+ fit: ImageFit => Value::from(match fit {
+ ImageFit::Cover => "cover",
+ ImageFit::Contain => "contain",
+ ImageFit::Stretch => "stretch",
+ })
+}
+
+/// Load an image from a path.
+#[comemo::memoize]
+fn load(world: Tracked<dyn World>, full: &str) -> StrResult<Image> {
+ let full = Path::new(full);
+ let buffer = world.file(full)?;
+ let ext = full.extension().and_then(OsStr::to_str).unwrap_or_default();
+ let format = match ext.to_lowercase().as_str() {
+ "png" => ImageFormat::Raster(RasterFormat::Png),
+ "jpg" | "jpeg" => ImageFormat::Raster(RasterFormat::Jpg),
+ "gif" => ImageFormat::Raster(RasterFormat::Gif),
+ "svg" | "svgz" => ImageFormat::Vector(VectorFormat::Svg),
+ _ => return Err("unknown image format".into()),
+ };
+ Image::new(buffer, format)
+}
diff --git a/library/src/visualize/line.rs b/library/src/visualize/line.rs
index 553e06c8..0e0a272f 100644
--- a/library/src/visualize/line.rs
+++ b/library/src/visualize/line.rs
@@ -1,6 +1,5 @@
use crate::prelude::*;
-/// # Line
/// A line from one point to another.
///
/// ## Example
@@ -26,20 +25,20 @@ use crate::prelude::*;
/// The angle at which the line points away from the origin. Mutually
/// exclusive with `end`.
///
-/// ## Category
-/// visualize
-#[func]
-#[capable(Layout)]
-#[derive(Debug, Hash)]
+/// Display: Line
+/// Category: visualize
+#[node(Construct, Layout)]
pub struct LineNode {
/// Where the line starts.
+ #[named]
+ #[default]
pub start: Axes<Rel<Length>>,
+
/// The offset from `start` where the line ends.
+ #[named]
+ #[default]
pub delta: Axes<Rel<Length>>,
-}
-#[node]
-impl LineNode {
/// How to stroke the line. This can be:
///
/// - A length specifying the stroke's thickness. The color is inherited,
@@ -52,12 +51,16 @@ impl LineNode {
/// ```example
/// #line(length: 100%, stroke: 2pt + red)
/// ```
- #[property(resolve, fold)]
- pub const STROKE: PartialStroke = PartialStroke::default();
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default]
+ pub stroke: PartialStroke,
+}
+impl Construct for LineNode {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let start = args.named("start")?.unwrap_or_default();
-
let delta = match args.named::<Axes<Rel<Length>>>("end")? {
Some(end) => end.zip(start).map(|(to, from)| to - from),
None => {
@@ -71,8 +74,7 @@ impl LineNode {
Axes::new(x, y)
}
};
-
- Ok(Self { start, delta }.pack())
+ Ok(Self::new().with_start(start).with_delta(delta).pack())
}
}
@@ -86,13 +88,13 @@ impl Layout for LineNode {
let stroke = styles.get(Self::STROKE).unwrap_or_default();
let origin = self
- .start
+ .start()
.resolve(styles)
.zip(regions.base())
.map(|(l, b)| l.relative_to(b));
let delta = self
- .delta
+ .delta()
.resolve(styles)
.zip(regions.base())
.map(|(l, b)| l.relative_to(b));
diff --git a/library/src/visualize/shape.rs b/library/src/visualize/shape.rs
index e5259d91..ef81a871 100644
--- a/library/src/visualize/shape.rs
+++ b/library/src/visualize/shape.rs
@@ -2,7 +2,6 @@ use std::f64::consts::SQRT_2;
use crate::prelude::*;
-/// # Rectangle
/// A rectangle with optional content.
///
/// ## Example
@@ -17,32 +16,28 @@ use crate::prelude::*;
/// ]
/// ```
///
-/// ## Parameters
-/// - body: `Content` (positional)
-/// The content to place into the rectangle.
-///
-/// When this is omitted, the rectangle takes on a default size of at most
-/// `{45pt}` by `{30pt}`.
-///
-/// - width: `Rel<Length>` (named)
-/// The rectangle's width, relative to its parent container.
-///
-/// - height: `Rel<Length>` (named)
-/// The rectangle's height, relative to its parent container.
-///
-/// ## Category
-/// visualize
-#[func]
-#[capable(Layout)]
-#[derive(Debug, Hash)]
+/// Display: Rectangle
+/// Category: visualize
+#[node(Layout)]
pub struct RectNode {
+ /// The content to place into the rectangle.
+ ///
+ /// When this is omitted, the rectangle takes on a default size of at most
+ /// `{45pt}` by `{30pt}`.
+ #[positional]
+ #[default]
pub body: Option<Content>,
+
+ /// The rectangle's width, relative to its parent container.
+ #[named]
+ #[default]
pub width: Smart<Rel<Length>>,
+
+ /// The rectangle's height, relative to its parent container.
+ #[named]
+ #[default]
pub height: Smart<Rel<Length>>,
-}
-#[node]
-impl RectNode {
/// How to fill the rectangle.
///
/// When setting a fill, the default stroke disappears. To create a
@@ -51,7 +46,9 @@ impl RectNode {
/// ```example
/// #rect(fill: blue)
/// ```
- pub const FILL: Option<Paint> = None;
+ #[settable]
+ #[default]
+ pub fill: Option<Paint>,
/// How to stroke the rectangle. This can be:
///
@@ -85,8 +82,11 @@ impl RectNode {
/// rect(stroke: 2pt + red),
/// )
/// ```
- #[property(resolve, fold)]
- pub const STROKE: Smart<Sides<Option<Option<PartialStroke>>>> = Smart::Auto;
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default]
+ pub stroke: Smart<Sides<Option<Option<PartialStroke>>>>,
/// How much to round the rectangle's corners, relative to the minimum of
/// the width and height divided by two. This can be:
@@ -122,8 +122,11 @@ impl RectNode {
/// ),
/// )
/// ```
- #[property(resolve, fold)]
- pub const RADIUS: Corners<Option<Rel<Length>>> = Corners::splat(Rel::zero());
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default]
+ pub radius: Corners<Option<Rel<Length>>>,
/// How much to pad the rectangle's content.
///
@@ -135,20 +138,19 @@ impl RectNode {
/// ```example
/// #rect(inset: 0pt)[Tight])
/// ```
- #[property(resolve, fold)]
- pub const INSET: Sides<Option<Rel<Length>>> = Sides::splat(Abs::pt(5.0).into());
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default(Sides::splat(Abs::pt(5.0).into()))]
+ pub inset: Sides<Option<Rel<Length>>>,
/// How much to expand the rectangle's size without affecting the layout.
/// See the [box's documentation]($func/box.outset) for more details.
- #[property(resolve, fold)]
- pub const OUTSET: Sides<Option<Rel<Length>>> = Sides::splat(Rel::zero());
-
- fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
- let width = args.named("width")?.unwrap_or_default();
- let height = args.named("height")?.unwrap_or_default();
- let body = args.eat()?;
- Ok(Self { body, width, height }.pack())
- }
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default]
+ pub outset: Sides<Option<Rel<Length>>>,
}
impl Layout for RectNode {
@@ -163,8 +165,8 @@ impl Layout for RectNode {
styles,
regions,
ShapeKind::Rect,
- &self.body,
- Axes::new(self.width, self.height),
+ &self.body(),
+ Axes::new(self.width(), self.height()),
styles.get(Self::FILL),
styles.get(Self::STROKE),
styles.get(Self::INSET),
@@ -174,7 +176,6 @@ impl Layout for RectNode {
}
}
-/// # Square
/// A square with optional content.
///
/// ## Example
@@ -189,69 +190,77 @@ impl Layout for RectNode {
/// ]
/// ```
///
-/// ## Parameters
-/// - body: `Content` (positional)
-/// The content to place into the square. The square expands to fit this
-/// content, keeping the 1-1 aspect ratio.
-///
-/// When this is omitted, the square takes on a default size of at most
-/// `{30pt}`.
-///
-/// - size: `Length` (named)
-/// The square's side length. This is mutually exclusive with `width` and
-/// `height`.
-///
-/// - width: `Rel<Length>` (named)
-/// The square's width. This is mutually exclusive with `size` and `height`.
-///
-/// In contrast to `size`, this can be relative to the parent container's
-/// width.
-///
-/// - height: `Rel<Length>` (named)
-/// The square's height. This is mutually exclusive with `size` and `width`.
-///
-/// In contrast to `size`, this can be relative to the parent container's
-/// height.
-///
-/// ## Category
-/// visualize
-#[func]
-#[capable(Layout)]
-#[derive(Debug, Hash)]
+/// Display: Square
+/// Category: visualize
+#[node(Construct, Layout)]
pub struct SquareNode {
+ /// The content to place into the square. The square expands to fit this
+ /// content, keeping the 1-1 aspect ratio.
+ ///
+ /// When this is omitted, the square takes on a default size of at most
+ /// `{30pt}`.
+ #[positional]
+ #[default]
pub body: Option<Content>,
+
+ /// The square's width. This is mutually exclusive with `size` and `height`.
+ ///
+ /// In contrast to `size`, this can be relative to the parent container's
+ /// width.
+ #[named]
+ #[default]
pub width: Smart<Rel<Length>>,
+
+ /// The square's height. This is mutually exclusive with `size` and `width`.
+ ///
+ /// In contrast to `size`, this can be relative to the parent container's
+ /// height.
+ #[named]
+ #[default]
pub height: Smart<Rel<Length>>,
-}
-#[node]
-impl SquareNode {
/// How to fill the square. See the
/// [rectangle's documentation]($func/rect.fill) for more details.
- pub const FILL: Option<Paint> = None;
+ #[settable]
+ #[default]
+ pub fill: Option<Paint>,
/// How to stroke the square. See the [rectangle's
/// documentation]($func/rect.stroke) for more details.
- #[property(resolve, fold)]
- pub const STROKE: Smart<Sides<Option<Option<PartialStroke>>>> = Smart::Auto;
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default]
+ pub stroke: Smart<Sides<Option<Option<PartialStroke>>>>,
/// How much to round the square's corners. See the [rectangle's
/// documentation]($func/rect.radius) for more details.
- #[property(resolve, fold)]
- pub const RADIUS: Corners<Option<Rel<Length>>> = Corners::splat(Rel::zero());
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default]
+ pub radius: Corners<Option<Rel<Length>>>,
/// How much to pad the square's content. See the [rectangle's
/// documentation]($func/rect.inset) for more details.
///
/// The default value is `{5pt}`.
- #[property(resolve, fold)]
- pub const INSET: Sides<Option<Rel<Length>>> = Sides::splat(Abs::pt(5.0).into());
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default(Sides::splat(Abs::pt(5.0).into()))]
+ pub inset: Sides<Option<Rel<Length>>>,
/// How much to expand the square's size without affecting the layout. See
/// the [rectangle's documentation]($func/rect.outset) for more details.
- #[property(resolve, fold)]
- pub const OUTSET: Sides<Option<Rel<Length>>> = Sides::splat(Rel::zero());
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default]
+ pub outset: Sides<Option<Rel<Length>>>,
+}
+impl Construct for SquareNode {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let size = args.named::<Smart<Length>>("size")?.map(|s| s.map(Rel::from));
let width = match size {
@@ -264,8 +273,12 @@ impl SquareNode {
size => size,
}
.unwrap_or_default();
- let body = args.eat()?;
- Ok(Self { body, width, height }.pack())
+ let body = args.eat::<Content>()?;
+ Ok(Self::new()
+ .with_body(body)
+ .with_width(width)
+ .with_height(height)
+ .pack())
}
}
@@ -281,8 +294,8 @@ impl Layout for SquareNode {
styles,
regions,
ShapeKind::Square,
- &self.body,
- Axes::new(self.width, self.height),
+ &self.body(),
+ Axes::new(self.width(), self.height()),
styles.get(Self::FILL),
styles.get(Self::STROKE),
styles.get(Self::INSET),
@@ -292,7 +305,6 @@ impl Layout for SquareNode {
}
}
-/// # Ellipse
/// An ellipse with optional content.
///
/// ## Example
@@ -308,59 +320,59 @@ impl Layout for SquareNode {
/// ]
/// ```
///
-/// ## Parameters
-/// - body: `Content` (positional)
-/// The content to place into the ellipse.
-///
-/// When this is omitted, the ellipse takes on a default size of at most
-/// `{45pt}` by `{30pt}`.
-///
-/// - width: `Rel<Length>` (named)
-/// The ellipse's width, relative to its parent container.
-///
-/// - height: `Rel<Length>` (named)
-/// The ellipse's height, relative to its parent container.
-///
-/// ## Category
-/// visualize
-#[func]
-#[capable(Layout)]
-#[derive(Debug, Hash)]
+/// Display: Ellipse
+/// Category: visualize
+#[node(Layout)]
pub struct EllipseNode {
+ /// The content to place into the ellipse.
+ ///
+ /// When this is omitted, the ellipse takes on a default size of at most
+ /// `{45pt}` by `{30pt}`.
+ #[positional]
+ #[default]
pub body: Option<Content>,
+
+ /// The ellipse's width, relative to its parent container.
+ #[named]
+ #[default]
pub width: Smart<Rel<Length>>,
+
+ /// The ellipse's height, relative to its parent container.
+ #[named]
+ #[default]
pub height: Smart<Rel<Length>>,
-}
-#[node]
-impl EllipseNode {
/// How to fill the ellipse. See the
/// [rectangle's documentation]($func/rect.fill) for more details.
- pub const FILL: Option<Paint> = None;
+ #[settable]
+ #[default]
+ pub fill: Option<Paint>,
/// How to stroke the ellipse. See the [rectangle's
/// documentation]($func/rect.stroke) for more details.
- #[property(resolve, fold)]
- pub const STROKE: Smart<Option<PartialStroke>> = Smart::Auto;
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default]
+ pub stroke: Smart<Option<PartialStroke>>,
/// How much to pad the ellipse's content. See the [rectangle's
/// documentation]($func/rect.inset) for more details.
///
/// The default value is `{5pt}`.
- #[property(resolve, fold)]
- pub const INSET: Sides<Option<Rel<Length>>> = Sides::splat(Abs::pt(5.0).into());
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default(Sides::splat(Abs::pt(5.0).into()))]
+ pub inset: Sides<Option<Rel<Length>>>,
/// How much to expand the ellipse's size without affecting the layout. See
/// the [rectangle's documentation]($func/rect.outset) for more details.
- #[property(resolve, fold)]
- pub const OUTSET: Sides<Option<Rel<Length>>> = Sides::splat(Rel::zero());
-
- fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
- let width = args.named("width")?.unwrap_or_default();
- let height = args.named("height")?.unwrap_or_default();
- let body = args.eat()?;
- Ok(Self { body, width, height }.pack())
- }
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default]
+ pub outset: Sides<Option<Rel<Length>>>,
}
impl Layout for EllipseNode {
@@ -375,8 +387,8 @@ impl Layout for EllipseNode {
styles,
regions,
ShapeKind::Ellipse,
- &self.body,
- Axes::new(self.width, self.height),
+ &self.body(),
+ Axes::new(self.width(), self.height()),
styles.get(Self::FILL),
styles.get(Self::STROKE).map(Sides::splat),
styles.get(Self::INSET),
@@ -386,7 +398,6 @@ impl Layout for EllipseNode {
}
}
-/// # Circle
/// A circle with optional content.
///
/// ## Example
@@ -423,40 +434,68 @@ impl Layout for EllipseNode {
/// In contrast to `size`, this can be relative to the parent container's
/// height.
///
-/// ## Category
-/// visualize
-#[func]
-#[capable(Layout)]
-#[derive(Debug, Hash)]
+/// Display: Circle
+/// Category: visualize
+#[node(Construct, Layout)]
pub struct CircleNode {
+ /// The content to place into the circle. The circle expands to fit this
+ /// content, keeping the 1-1 aspect ratio.
+ #[positional]
+ #[default]
pub body: Option<Content>,
+
+ /// The circle's width. This is mutually exclusive with `radius` and
+ /// `height`.
+ ///
+ /// In contrast to `size`, this can be relative to the parent container's
+ /// width.
+ #[named]
+ #[default]
pub width: Smart<Rel<Length>>,
+
+ /// The circle's height.This is mutually exclusive with `radius` and
+ /// `width`.
+ ///
+ /// In contrast to `size`, this can be relative to the parent container's
+ /// height.
+ #[named]
+ #[default]
pub height: Smart<Rel<Length>>,
-}
-#[node]
-impl CircleNode {
/// How to fill the circle. See the
/// [rectangle's documentation]($func/rect.fill) for more details.
- pub const FILL: Option<Paint> = None;
+ #[settable]
+ #[default]
+ pub fill: Option<Paint>,
/// How to stroke the circle. See the [rectangle's
/// documentation]($func/rect.stroke) for more details.
- #[property(resolve, fold)]
- pub const STROKE: Smart<Option<PartialStroke>> = Smart::Auto;
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default(Smart::Auto)]
+ pub stroke: Smart<Option<PartialStroke>>,
/// How much to pad the circle's content. See the [rectangle's
/// documentation]($func/rect.inset) for more details.
///
/// The default value is `{5pt}`.
- #[property(resolve, fold)]
- pub const INSET: Sides<Option<Rel<Length>>> = Sides::splat(Abs::pt(5.0).into());
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default(Sides::splat(Abs::pt(5.0).into()))]
+ pub inset: Sides<Option<Rel<Length>>>,
/// How much to expand the circle's size without affecting the layout. See
/// the [rectangle's documentation]($func/rect.outset) for more details.
- #[property(resolve, fold)]
- pub const OUTSET: Sides<Option<Rel<Length>>> = Sides::splat(Rel::zero());
+ #[settable]
+ #[resolve]
+ #[fold]
+ #[default]
+ pub outset: Sides<Option<Rel<Length>>>,
+}
+impl Construct for CircleNode {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let size = args
.named::<Smart<Length>>("radius")?
@@ -471,8 +510,12 @@ impl CircleNode {
size => size,
}
.unwrap_or_default();
- let body = args.eat()?;
- Ok(Self { body, width, height }.pack())
+ let body = args.eat::<Content>()?;
+ Ok(Self::new()
+ .with_body(body)
+ .with_width(width)
+ .with_height(height)
+ .pack())
}
}
@@ -488,8 +531,8 @@ impl Layout for CircleNode {
styles,
regions,
ShapeKind::Circle,
- &self.body,
- Axes::new(self.width, self.height),
+ &self.body(),
+ Axes::new(self.width(), self.height()),
styles.get(Self::FILL),
styles.get(Self::STROKE).map(Sides::splat),
styles.get(Self::INSET),