From b471ac7d590abd2398ce25193b4e4df373bf2e9c Mon Sep 17 00:00:00 2001 From: Laurenz Date: Mon, 11 Sep 2023 14:40:22 +0200 Subject: First-class types Makes types first-class values. --- crates/typst-library/src/visualize/image.rs | 119 ++++++++--------- crates/typst-library/src/visualize/line.rs | 52 +------- crates/typst-library/src/visualize/mod.rs | 37 ++---- crates/typst-library/src/visualize/path.rs | 39 +++--- crates/typst-library/src/visualize/polygon.rs | 176 +++++++++++++------------- crates/typst-library/src/visualize/shape.rs | 106 ++++++---------- 6 files changed, 217 insertions(+), 312 deletions(-) (limited to 'crates/typst-library/src/visualize') diff --git a/crates/typst-library/src/visualize/image.rs b/crates/typst-library/src/visualize/image.rs index a06509dd..e6269198 100644 --- a/crates/typst-library/src/visualize/image.rs +++ b/crates/typst-library/src/visualize/image.rs @@ -18,7 +18,7 @@ use crate::text::families; /// in the resulting PDF. Make sure to double-check embedded SVG images. If you /// have an issue, also feel free to report it on [GitHub][gh-svg]. /// -/// ## Example { #example } +/// # Example /// ```example /// #figure( /// image("molecular.jpg", width: 80%), @@ -30,14 +30,7 @@ use crate::text::families; /// ``` /// /// [gh-svg]: https://github.com/typst/typst/issues?q=is%3Aopen+is%3Aissue+label%3Asvg -/// -/// Display: Image -/// Category: visualize -#[element(Layout, LocalName, Figurable)] -#[scope( - scope.define("decode", image_decode_func()); - scope -)] +#[elem(scope, Layout, LocalName, Figurable)] pub struct ImageElem { /// Path to an image file. #[required] @@ -73,59 +66,58 @@ pub struct ImageElem { pub fit: ImageFit, } -/// Decode a raster or vector graphic from bytes or a string. -/// -/// ## Example { #example } -/// ```example -/// #let original = read("diagram.svg") -/// #let changed = original.replace( -/// "#2B80FF", // blue -/// green.hex(), -/// ) -/// -/// #image.decode(original) -/// #image.decode(changed) -/// ``` -/// -/// Display: Decode Image -/// Category: visualize -#[func] -pub fn image_decode( - /// The data to decode as an image. Can be a string for SVGs. - data: Readable, - /// The image's format. Detected automatically by default. - #[named] - format: Option>, - /// The width of the image. - #[named] - width: Option>>, - /// The height of the image. - #[named] - height: Option>>, - /// A text describing the image. - #[named] - alt: Option>, - /// How the image should adjust itself to a given area. - #[named] - fit: Option, -) -> StrResult { - let mut elem = ImageElem::new(EcoString::new(), data); - if let Some(format) = format { - elem.push_format(format); - } - if let Some(width) = width { - elem.push_width(width); - } - if let Some(height) = height { - elem.push_height(height); - } - if let Some(alt) = alt { - elem.push_alt(alt); - } - if let Some(fit) = fit { - elem.push_fit(fit); +#[scope] +impl ImageElem { + /// Decode a raster or vector graphic from bytes or a string. + /// + /// ```example + /// #let original = read("diagram.svg") + /// #let changed = original.replace( + /// "#2B80FF", // blue + /// green.to-hex(), + /// ) + /// + /// #image.decode(original) + /// #image.decode(changed) + /// ``` + #[func(title = "Decode Image")] + pub fn decode( + /// The data to decode as an image. Can be a string for SVGs. + data: Readable, + /// The image's format. Detected automatically by default. + #[named] + format: Option>, + /// The width of the image. + #[named] + width: Option>>, + /// The height of the image. + #[named] + height: Option>>, + /// A text describing the image. + #[named] + alt: Option>, + /// How the image should adjust itself to a given area. + #[named] + fit: Option, + ) -> StrResult { + let mut elem = ImageElem::new(EcoString::new(), data); + if let Some(format) = format { + elem.push_format(format); + } + if let Some(width) = width { + elem.push_width(width); + } + if let Some(height) = height { + elem.push_height(height); + } + if let Some(alt) = alt { + elem.push_alt(alt); + } + if let Some(fit) = fit { + elem.push_fit(fit); + } + Ok(elem.pack()) } - Ok(elem.pack()) } impl Layout for ImageElem { @@ -175,8 +167,7 @@ impl Layout for ImageElem { let sizing = Axes::new(self.width(styles), self.height(styles)); let region = sizing - .zip(regions.base()) - .map(|(s, r)| s.map(|v| v.resolve(styles).relative_to(r))) + .zip_map(regions.base(), |s, r| s.map(|v| v.resolve(styles).relative_to(r))) .unwrap_or(regions.base()); let expand = sizing.as_ref().map(Smart::is_custom) | regions.expand; @@ -217,7 +208,7 @@ impl Layout for ImageElem { // process. let mut frame = Frame::new(fitted); frame.push(Point::zero(), FrameItem::Image(image, fitted, self.span())); - frame.resize(target, Align::CENTER_HORIZON); + frame.resize(target, Axes::splat(FixedAlign::Center)); // Create a clipping group if only part of the image should be visible. if fit == ImageFit::Cover && !target.fits(fitted) { diff --git a/crates/typst-library/src/visualize/line.rs b/crates/typst-library/src/visualize/line.rs index a476ffa7..9960a2d3 100644 --- a/crates/typst-library/src/visualize/line.rs +++ b/crates/typst-library/src/visualize/line.rs @@ -2,7 +2,7 @@ use crate::prelude::*; /// A line from one point to another. /// -/// ## Example { #example } +/// # Example /// ```example /// #set page(height: 100pt) /// @@ -13,10 +13,7 @@ use crate::prelude::*; /// stroke: 2pt + maroon, /// ) /// ``` -/// -/// Display: Line -/// Category: visualize -#[element(Layout)] +#[elem(Layout)] pub struct LineElem { /// The start point of the line. /// @@ -37,42 +34,7 @@ pub struct LineElem { /// respected if `end` is `none`. pub angle: Angle, - /// How to stroke the line. This can be: - /// - /// - A length specifying the stroke's thickness. The color is inherited, - /// defaulting to black. - /// - A color to use for the stroke. The thickness is inherited, defaulting - /// to `{1pt}`. - /// - A stroke combined from color and thickness using the `+` operator as - /// in `{2pt + red}`. - /// - A stroke described by a dictionary with any of the following keys: - /// - `paint`: The [color]($type/color) to use for the stroke. - /// - `thickness`: The stroke's thickness as a [length]($type/length). - /// - `cap`: How the line terminates. One of `{"butt"}`, `{"round"}`, or - /// `{"square"}`. - /// - `join`: How sharp turns of a contour are rendered. One of - /// `{"miter"}`, `{"round"}`, or `{"bevel"}`. Not applicable to lines - /// but to [polygons]($func/polygon) or [paths]($func/path). - /// - `miter-limit`: Number at which protruding sharp angles are rendered - /// with a bevel instead. The higher the number, the sharper an angle - /// can be before it is bevelled. Only applicable if `join` is - /// `{"miter"}`. Defaults to `{4.0}`. - /// - `dash`: The dash pattern to use. Can be any of the following: - /// - One of the predefined patterns `{"solid"}`, `{"dotted"}`, - /// `{"densely-dotted"}`, `{"loosely-dotted"}`, `{"dashed"}`, - /// `{"densely-dashed"}`, `{"loosely-dashed"}`, `{"dash-dotted"}`, - /// `{"densely-dash-dotted"}` or `{"loosely-dash-dotted"}` - /// - An [array]($type/array) with alternating lengths for dashes and - /// gaps. You can also use the string `{"dot"}` for a length equal to - /// the line thickness. - /// - A [dictionary]($type/dictionary) with the keys `array` (same as - /// the array above), and `phase` (of type [length]($type/length)), - /// which defines where in the pattern to start drawing. - /// - /// On a `stroke` object, you can access any of the fields mentioned in the - /// dictionary format above. For example, `{(2pt + blue).thickness}` is - /// `{2pt}`, `{(2pt + blue).miter-limit}` is `{4.0}` (the default), and so - /// on. + /// How to [stroke]($stroke) the line. /// /// ```example /// #set line(length: 100%) @@ -86,7 +48,7 @@ pub struct LineElem { /// ``` #[resolve] #[fold] - pub stroke: PartialStroke, + pub stroke: Stroke, } impl Layout for LineElem { @@ -97,10 +59,8 @@ impl Layout for LineElem { styles: StyleChain, regions: Regions, ) -> SourceResult { - let resolve = |axes: Axes>| { - axes.zip(regions.base()).map(|(l, b)| l.relative_to(b)) - }; - + let resolve = + |axes: Axes>| axes.zip_map(regions.base(), Rel::relative_to); let start = resolve(self.start(styles)); let delta = self.end(styles).map(|end| resolve(end) - start).unwrap_or_else(|| { diff --git a/crates/typst-library/src/visualize/mod.rs b/crates/typst-library/src/visualize/mod.rs index ea873f44..a013853f 100644 --- a/crates/typst-library/src/visualize/mod.rs +++ b/crates/typst-library/src/visualize/mod.rs @@ -16,30 +16,15 @@ use crate::prelude::*; /// Hook up all visualize definitions. pub(super) fn define(global: &mut Scope) { - global.define("image", ImageElem::func()); - global.define("line", LineElem::func()); - global.define("rect", RectElem::func()); - global.define("square", SquareElem::func()); - global.define("ellipse", EllipseElem::func()); - global.define("circle", CircleElem::func()); - global.define("polygon", PolygonElem::func()); - global.define("path", PathElem::func()); - global.define("black", Color::BLACK); - global.define("gray", Color::GRAY); - global.define("silver", Color::SILVER); - global.define("white", Color::WHITE); - global.define("navy", Color::NAVY); - global.define("blue", Color::BLUE); - global.define("aqua", Color::AQUA); - global.define("teal", Color::TEAL); - global.define("eastern", Color::EASTERN); - global.define("purple", Color::PURPLE); - global.define("fuchsia", Color::FUCHSIA); - global.define("maroon", Color::MAROON); - global.define("red", Color::RED); - global.define("orange", Color::ORANGE); - global.define("yellow", Color::YELLOW); - global.define("olive", Color::OLIVE); - global.define("green", Color::GREEN); - global.define("lime", Color::LIME); + global.category("visualize"); + global.define_type::(); + global.define_type::(); + global.define_elem::(); + global.define_elem::(); + global.define_elem::(); + global.define_elem::(); + global.define_elem::(); + global.define_elem::(); + global.define_elem::(); + global.define_elem::(); } diff --git a/crates/typst-library/src/visualize/path.rs b/crates/typst-library/src/visualize/path.rs index d78abce1..c252e95f 100644 --- a/crates/typst-library/src/visualize/path.rs +++ b/crates/typst-library/src/visualize/path.rs @@ -7,7 +7,7 @@ use PathVertex::{AllControlPoints, MirroredControlPoint, Vertex}; /// A path through a list of points, connected by Bezier curves. /// -/// ## Example { #example } +/// # Example /// ```example /// #path( /// fill: blue.lighten(80%), @@ -18,26 +18,24 @@ use PathVertex::{AllControlPoints, MirroredControlPoint, Vertex}; /// ((50%, 0pt), (40pt, 0pt)), /// ) /// ``` -/// -/// Display: Path -/// Category: visualize -#[element(Layout)] +#[elem(Layout)] pub struct PathElem { - /// How to fill the path. See the - /// [rectangle's documentation]($func/rect.fill) for more details. + /// How to fill the path. + /// + /// When setting a fill, the default stroke disappears. To create a + /// rectangle with both fill and stroke, you have to configure both. /// - /// Currently all paths are filled according to the - /// [non-zero winding rule](https://en.wikipedia.org/wiki/Nonzero-rule). + /// Currently all paths are filled according to the [non-zero winding + /// rule](https://en.wikipedia.org/wiki/Nonzero-rule). pub fill: Option, - /// How to stroke the path. This can be: + /// How to [stroke]($stroke) the path. This can be: /// - /// See the [line's documentation]($func/line.stroke) for more details. Can - /// be set to `{none}` to disable the stroke or to `{auto}` for a stroke of - /// `{1pt}` black if and if only if no fill is given. + /// Can be set to `{none}` to disable the stroke or to `{auto}` for a + /// stroke of `{1pt}` black if and if only if no fill is given. #[resolve] #[fold] - pub stroke: Smart>, + pub stroke: Smart>, /// Whether to close this path with one last bezier curve. This curve will /// takes into account the adjacent control points. If you want to close @@ -50,8 +48,8 @@ pub struct PathElem { /// /// Each vertex can be defined in 3 ways: /// - /// - A regular point, as given to the [`line`]($func/line) or - /// [`polygon`]($func/polygon) function. + /// - A regular point, as given to the [`line`]($line) or + /// [`polygon`]($polygon) function. /// - An array of two points, the first being the vertex and the second /// being the control point. The control point is expressed relative to /// the vertex and is mirrored to get the second control point. The given @@ -60,7 +58,7 @@ pub struct PathElem { /// the curve going out of this vertex. /// - An array of three points, the first being the vertex and the next /// being the control points (control point for curves coming in and out, - /// respectively) + /// respectively). #[variadic] pub vertices: Vec, } @@ -75,8 +73,7 @@ impl Layout for PathElem { ) -> SourceResult { let resolve = |axes: Axes>| { axes.resolve(styles) - .zip(regions.base()) - .map(|(l, b)| l.relative_to(b)) + .zip_map(regions.base(), Rel::relative_to) .to_point() }; @@ -136,9 +133,9 @@ impl Layout for PathElem { // Prepare fill and stroke. let fill = self.fill(styles); let stroke = match self.stroke(styles) { - Smart::Auto if fill.is_none() => Some(Stroke::default()), + Smart::Auto if fill.is_none() => Some(FixedStroke::default()), Smart::Auto => None, - Smart::Custom(stroke) => stroke.map(PartialStroke::unwrap_or_default), + Smart::Custom(stroke) => stroke.map(Stroke::unwrap_or_default), }; let mut frame = Frame::new(size); diff --git a/crates/typst-library/src/visualize/polygon.rs b/crates/typst-library/src/visualize/polygon.rs index b244b2e9..9f573467 100644 --- a/crates/typst-library/src/visualize/polygon.rs +++ b/crates/typst-library/src/visualize/polygon.rs @@ -6,7 +6,7 @@ use crate::prelude::*; /// /// The polygon is defined by its corner points and is closed automatically. /// -/// ## Example { #example } +/// # Example /// ```example /// #polygon( /// fill: blue.lighten(80%), @@ -17,37 +17,102 @@ use crate::prelude::*; /// (0%, 2cm), /// ) /// ``` -/// -/// Display: Polygon -/// Category: visualize -#[element(Layout)] -#[scope( - scope.define("regular", polygon_regular_func()); - scope -)] +#[elem(scope, Layout)] pub struct PolygonElem { - /// How to fill the polygon. See the - /// [rectangle's documentation]($func/rect.fill) for more details. + /// How to fill the polygon. + /// + /// When setting a fill, the default stroke disappears. To create a + /// rectangle with both fill and stroke, you have to configure both. /// /// Currently all polygons are filled according to the /// [non-zero winding rule](https://en.wikipedia.org/wiki/Nonzero-rule). pub fill: Option, - /// How to stroke the polygon. This can be: + /// How to [stroke]($stroke) the polygon. This can be: /// - /// See the [line's documentation]($func/line.stroke) for more details. Can - /// be set to `{none}` to disable the stroke or to `{auto}` for a stroke of - /// `{1pt}` black if and if only if no fill is given. + /// Can be set to `{none}` to disable the stroke or to `{auto}` for a + /// stroke of `{1pt}` black if and if only if no fill is given. #[resolve] #[fold] - pub stroke: Smart>, + pub stroke: Smart>, /// The vertices of the polygon. Each point is specified as an array of two - /// [relative lengths]($type/relative-length). + /// [relative lengths]($relative). #[variadic] pub vertices: Vec>>, } +#[scope] +impl PolygonElem { + /// A regular polygon, defined by its size and number of vertices. + /// + /// ```example + /// #polygon.regular( + /// fill: blue.lighten(80%), + /// stroke: blue, + /// size: 30pt, + /// vertices: 3, + /// ) + /// ``` + #[func(title = "Regular Polygon")] + pub fn regular( + /// How to fill the polygon. See the general + /// [polygon's documentation]($polygon.fill) for more details. + #[named] + fill: Option>, + + /// How to stroke the polygon. See the general + /// [polygon's documentation]($polygon.stroke) for more details. + #[named] + stroke: Option>>, + + /// The diameter of the [circumcircle](https://en.wikipedia.org/wiki/Circumcircle) + /// of the regular polygon. + #[named] + #[default(Em::one().into())] + size: Length, + + /// The number of vertices in the polygon. + #[named] + #[default(3)] + vertices: u64, + ) -> Content { + let radius = size / 2.0; + let angle = |i: f64| { + 2.0 * PI * i / (vertices as f64) + PI * (1.0 / 2.0 - 1.0 / vertices as f64) + }; + let (horizontal_offset, vertical_offset) = (0..=vertices) + .map(|v| { + ( + (radius * angle(v as f64).cos()) + radius, + (radius * angle(v as f64).sin()) + radius, + ) + }) + .fold((radius, radius), |(min_x, min_y), (v_x, v_y)| { + ( + if min_x < v_x { min_x } else { v_x }, + if min_y < v_y { min_y } else { v_y }, + ) + }); + let vertices = (0..=vertices) + .map(|v| { + let x = (radius * angle(v as f64).cos()) + radius - horizontal_offset; + let y = (radius * angle(v as f64).sin()) + radius - vertical_offset; + Axes::new(x, y).map(Rel::from) + }) + .collect(); + + let mut elem = PolygonElem::new(vertices); + if let Some(fill) = fill { + elem.push_fill(fill); + } + if let Some(stroke) = stroke { + elem.push_stroke(stroke); + } + elem.pack() + } +} + impl Layout for PolygonElem { #[tracing::instrument(name = "PolygonElem::layout", skip_all)] fn layout( @@ -60,10 +125,7 @@ impl Layout for PolygonElem { .vertices() .iter() .map(|c| { - c.resolve(styles) - .zip(regions.base()) - .map(|(l, b)| l.relative_to(b)) - .to_point() + c.resolve(styles).zip_map(regions.base(), Rel::relative_to).to_point() }) .collect(); @@ -78,9 +140,9 @@ impl Layout for PolygonElem { // Prepare fill and stroke. let fill = self.fill(styles); let stroke = match self.stroke(styles) { - Smart::Auto if fill.is_none() => Some(Stroke::default()), + Smart::Auto if fill.is_none() => Some(FixedStroke::default()), Smart::Auto => None, - Smart::Custom(stroke) => stroke.map(PartialStroke::unwrap_or_default), + Smart::Custom(stroke) => stroke.map(Stroke::unwrap_or_default), }; // Construct a closed path given all points. @@ -97,71 +159,3 @@ impl Layout for PolygonElem { Ok(Fragment::frame(frame)) } } - -/// A regular polygon, defined by its size and number of vertices. -/// -/// ## Example { #example } -/// ```example -/// #polygon.regular( -/// fill: blue.lighten(80%), -/// stroke: blue, -/// size: 30pt, -/// vertices: 3, -/// ) -/// ``` -/// -/// Display: Regular Polygon -/// Category: visualize -#[func] -pub fn polygon_regular( - /// How to fill the polygon. See the general - /// [polygon's documentation]($func/polygon.fill) for more details. - #[named] - fill: Option>, - - /// How to stroke the polygon. See the general - /// [polygon's documentation]($func/polygon.stroke) for more details. - #[named] - stroke: Option>>, - - /// The diameter of the circumcircle of the regular polygon (https://en.wikipedia.org/wiki/Circumcircle). - #[named] - #[default(Em::one().into())] - size: Length, - - /// The number of vertices in the polygon. - #[named] - #[default(3)] - vertices: u64, -) -> Content { - let radius = size / 2.0; - let angle = |i: f64| { - 2.0 * PI * i / (vertices as f64) + PI * (1.0 / 2.0 - 1.0 / vertices as f64) - }; - let (horizontal_offset, vertical_offset) = (0..=vertices) - .map(|v| { - ( - (radius * angle(v as f64).cos()) + radius, - (radius * angle(v as f64).sin()) + radius, - ) - }) - .fold((radius, radius), |(min_x, min_y), (v_x, v_y)| { - (if min_x < v_x { min_x } else { v_x }, if min_y < v_y { min_y } else { v_y }) - }); - let vertices = (0..=vertices) - .map(|v| { - let x = (radius * angle(v as f64).cos()) + radius - horizontal_offset; - let y = (radius * angle(v as f64).sin()) + radius - vertical_offset; - Axes::new(x, y).map(Rel::from) - }) - .collect(); - - let mut elem = PolygonElem::new(vertices); - if let Some(fill) = fill { - elem.push_fill(fill); - } - if let Some(stroke) = stroke { - elem.push_stroke(stroke); - } - elem.pack() -} diff --git a/crates/typst-library/src/visualize/shape.rs b/crates/typst-library/src/visualize/shape.rs index 6129b70b..64d1ece6 100644 --- a/crates/typst-library/src/visualize/shape.rs +++ b/crates/typst-library/src/visualize/shape.rs @@ -4,7 +4,7 @@ use crate::prelude::*; /// A rectangle with optional content. /// -/// ## Example { #example } +/// # Example /// ```example /// // Without content. /// #rect(width: 35%, height: 30pt) @@ -15,10 +15,7 @@ use crate::prelude::*; /// to fit the content. /// ] /// ``` -/// -/// Display: Rectangle -/// Category: visualize -#[element(Layout)] +#[elem(title = "Rectangle", Layout)] pub struct RectElem { /// The rectangle's width, relative to its parent container. pub width: Smart>, @@ -41,8 +38,7 @@ pub struct RectElem { /// - `{none}` to disable stroking /// - `{auto}` for a stroke of `{1pt + black}` if and if only if no fill is /// given. - /// - Any kind of stroke that can also be used for - /// [lines]($func/line.stroke). + /// - Any kind of [stroke]($stroke) /// - A dictionary describing the stroke for each side inidvidually. The /// dictionary can contain the following keys in order of precedence: /// - `top`: The top stroke. @@ -65,7 +61,7 @@ pub struct RectElem { /// ``` #[resolve] #[fold] - pub stroke: Smart>>>, + pub stroke: Smart>>>, /// How much to round the rectangle's corners, relative to the minimum of /// the width and height divided by two. This can be: @@ -106,20 +102,14 @@ pub struct RectElem { pub radius: Corners>>, /// How much to pad the rectangle's content. - /// - /// _Note:_ When the rectangle contains text, its exact size depends on the - /// current [text edges]($func/text.top-edge). - /// - /// ```example - /// #rect(inset: 0pt)[Tight] - /// ``` + /// See the [box's documentation]($box.outset) for more details. #[resolve] #[fold] #[default(Sides::splat(Abs::pt(5.0).into()))] pub inset: Sides>>, /// How much to expand the rectangle's size without affecting the layout. - /// See the [box's documentation]($func/box.outset) for more details. + /// See the [box's documentation]($box.outset) for more details. #[resolve] #[fold] pub outset: Sides>>, @@ -159,7 +149,7 @@ impl Layout for RectElem { /// A square with optional content. /// -/// ## Example { #example } +/// # Example /// ```example /// // Without content. /// #square(size: 40pt) @@ -170,10 +160,7 @@ impl Layout for RectElem { /// sized to fit. /// ] /// ``` -/// -/// Display: Square -/// Category: visualize -#[element(Layout)] +#[elem(Layout)] pub struct SquareElem { /// The square's side length. This is mutually exclusive with `width` and /// `height`. @@ -203,31 +190,31 @@ pub struct SquareElem { })] pub height: Smart>, - /// How to fill the square. See the - /// [rectangle's documentation]($func/rect.fill) for more details. + /// How to fill the square. See the [rectangle's documentation]($rect.fill) + /// for more details. pub fill: Option, - /// How to stroke the square. See the [rectangle's - /// documentation]($func/rect.stroke) for more details. + /// How to stroke the square. See the + /// [rectangle's documentation]($rect.stroke) for more details. #[resolve] #[fold] - pub stroke: Smart>>>, + pub stroke: Smart>>>, - /// How much to round the square's corners. See the [rectangle's - /// documentation]($func/rect.radius) for more details. + /// How much to round the square's corners. See the + /// [rectangle's documentation]($rect.radius) for more details. #[resolve] #[fold] pub radius: Corners>>, - /// How much to pad the square's content. See the [rectangle's - /// documentation]($func/rect.inset) for more details. + /// How much to pad the square's content. See the + /// [box's documentation]($box.inset) for more details. #[resolve] #[fold] #[default(Sides::splat(Abs::pt(5.0).into()))] pub inset: Sides>>, /// How much to expand the square's size without affecting the layout. See - /// the [rectangle's documentation]($func/rect.outset) for more details. + /// the [box's documentation]($box.outset) for more details. #[resolve] #[fold] pub outset: Sides>>, @@ -268,7 +255,7 @@ impl Layout for SquareElem { /// An ellipse with optional content. /// -/// ## Example { #example } +/// # Example /// ```example /// // Without content. /// #ellipse(width: 35%, height: 30pt) @@ -280,10 +267,7 @@ impl Layout for SquareElem { /// to fit the content. /// ] /// ``` -/// -/// Display: Ellipse -/// Category: visualize -#[element(Layout)] +#[elem(Layout)] pub struct EllipseElem { /// The ellipse's width, relative to its parent container. pub width: Smart>, @@ -291,25 +275,25 @@ pub struct EllipseElem { /// The ellipse's height, relative to its parent container. pub height: Smart>, - /// How to fill the ellipse. See the - /// [rectangle's documentation]($func/rect.fill) for more details. + /// How to fill the ellipse. See the [rectangle's documentation]($rect.fill) + /// for more details. pub fill: Option, - /// How to stroke the ellipse. See the [rectangle's - /// documentation]($func/rect.stroke) for more details. + /// How to stroke the ellipse. See the + /// [rectangle's documentation]($rect.stroke) for more details. #[resolve] #[fold] - pub stroke: Smart>, + pub stroke: Smart>, - /// How much to pad the ellipse's content. See the [rectangle's - /// documentation]($func/rect.inset) for more details. + /// How much to pad the ellipse's content. See the + /// [box's documentation]($box.inset) for more details. #[resolve] #[fold] #[default(Sides::splat(Abs::pt(5.0).into()))] pub inset: Sides>>, /// How much to expand the ellipse's size without affecting the layout. See - /// the [rectangle's documentation]($func/rect.outset) for more details. + /// the [box's documentation]($box.outset) for more details. #[resolve] #[fold] pub outset: Sides>>, @@ -349,7 +333,7 @@ impl Layout for EllipseElem { /// A circle with optional content. /// -/// ## Example { #example } +/// # Example /// ```example /// // Without content. /// #circle(radius: 25pt) @@ -361,10 +345,7 @@ impl Layout for EllipseElem { /// sized to fit. /// ] /// ``` -/// -/// Display: Circle -/// Category: visualize -#[element(Layout)] +#[elem(Layout)] pub struct CircleElem { /// The circle's radius. This is mutually exclusive with `width` and /// `height`. @@ -398,26 +379,26 @@ pub struct CircleElem { })] pub height: Smart>, - /// How to fill the circle. See the - /// [rectangle's documentation]($func/rect.fill) for more details. + /// How to fill the circle. See the [rectangle's documentation]($rect.fill) + /// for more details. pub fill: Option, - /// How to stroke the circle. See the [rectangle's - /// documentation]($func/rect.stroke) for more details. + /// How to stroke the circle. See the + /// [rectangle's documentation]($rect.stroke) for more details. #[resolve] #[fold] #[default(Smart::Auto)] - pub stroke: Smart>, + pub stroke: Smart>, - /// How much to pad the circle's content. See the [rectangle's - /// documentation]($func/rect.inset) for more details. + /// How much to pad the circle's content. See the + /// [box's documentation]($box.inset) for more details. #[resolve] #[fold] #[default(Sides::splat(Abs::pt(5.0).into()))] pub inset: Sides>>, /// How much to expand the circle's size without affecting the layout. See - /// the [rectangle's documentation]($func/rect.outset) for more details. + /// the [box's documentation]($box.outset) for more details. #[resolve] #[fold] pub outset: Sides>>, @@ -464,15 +445,14 @@ fn layout( body: &Option, sizing: Axes>>, fill: Option, - stroke: Smart>>>, + stroke: Smart>>>, mut inset: Sides>, outset: Sides>, radius: Corners>, span: Span, ) -> SourceResult { let resolved = sizing - .zip(regions.base()) - .map(|(s, r)| s.map(|v| v.resolve(styles).relative_to(r))); + .zip_map(regions.base(), |s, r| s.map(|v| v.resolve(styles).relative_to(r))); let mut frame; if let Some(child) = body { @@ -517,11 +497,9 @@ fn layout( // Prepare stroke. let stroke = match stroke { - Smart::Auto if fill.is_none() => Sides::splat(Some(Stroke::default())), + Smart::Auto if fill.is_none() => Sides::splat(Some(FixedStroke::default())), Smart::Auto => Sides::splat(None), - Smart::Custom(strokes) => { - strokes.map(|s| s.map(PartialStroke::unwrap_or_default)) - } + Smart::Custom(strokes) => strokes.map(|s| s.map(Stroke::unwrap_or_default)), }; // Add fill and/or stroke. -- cgit v1.2.3