diff options
| author | Martin Haug <mhaug@live.de> | 2022-03-16 12:36:50 +0100 |
|---|---|---|
| committer | Martin Haug <mhaug@live.de> | 2022-03-16 12:36:50 +0100 |
| commit | 4d617bcd67f9e42218da190dc9a0bf2f10d4b78d (patch) | |
| tree | fea275e9321004c15ed7d1def9f3749641f648ed /src/library | |
| parent | 288a926feae1e73dff5a6b103aa920d6f7eb0f35 (diff) | |
`LineNode`
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/graphics/line.rs | 61 | ||||
| -rw-r--r-- | src/library/graphics/mod.rs | 2 | ||||
| -rw-r--r-- | src/library/mod.rs | 12 |
3 files changed, 75 insertions, 0 deletions
diff --git a/src/library/graphics/line.rs b/src/library/graphics/line.rs new file mode 100644 index 00000000..141abb08 --- /dev/null +++ b/src/library/graphics/line.rs @@ -0,0 +1,61 @@ +use crate::library::prelude::*; + +/// Display a line without affecting the layout. +#[derive(Debug, Hash)] +pub struct LineNode(Spec<Linear>, Spec<Linear>); + +#[node] +impl LineNode { + /// How the stroke the line. + pub const STROKE: Smart<Paint> = Smart::Auto; + /// The line's thickness. + pub const THICKNESS: Length = Length::pt(1.0); + + fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> { + let origin = args.named::<Spec<Linear>>("origin")?.unwrap_or_default(); + let to = match args.named::<Spec<Linear>>("to")? { + Some(to) => to.zip(origin).map(|(to, from)| to - from), + None => { + let length = + args.named::<Linear>("length")?.unwrap_or(Length::cm(1.0).into()); + let angle = args.named::<Angle>("angle")?.unwrap_or_default(); + + let x = angle.cos() * length; + let y = angle.sin() * length; + + Spec::new(x, y) + } + }; + + Ok(Content::inline(Self(origin, to))) + } +} + +impl Layout for LineNode { + fn layout( + &self, + _: &mut Context, + regions: &Regions, + styles: StyleChain, + ) -> TypResult<Vec<Arc<Frame>>> { + let target = regions.expand.select(regions.first, Size::zero()); + let mut frame = Frame::new(target); + + let thickness = styles.get(Self::THICKNESS); + let stroke = Some(Stroke { + paint: styles.get(Self::STROKE).unwrap_or(Color::BLACK.into()), + thickness, + }); + + let resolved_origin = + self.0.zip(regions.base).map(|(l, b)| Linear::resolve(l, b)); + let resolved_to = self.1.zip(regions.base).map(|(l, b)| Linear::resolve(l, b)); + + let geometry = Geometry::Line(resolved_to.into()); + + let shape = Shape { geometry, fill: None, stroke }; + frame.prepend(resolved_origin.into(), Element::Shape(shape)); + + Ok(vec![Arc::new(frame)]) + } +} diff --git a/src/library/graphics/mod.rs b/src/library/graphics/mod.rs index 353f09ca..e9a6188f 100644 --- a/src/library/graphics/mod.rs +++ b/src/library/graphics/mod.rs @@ -2,10 +2,12 @@ mod hide; mod image; +mod line; mod shape; mod transform; pub use self::image::*; pub use hide::*; +pub use line::*; pub use shape::*; pub use transform::*; diff --git a/src/library/mod.rs b/src/library/mod.rs index 8f00e5fe..88f003c2 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -53,6 +53,7 @@ pub fn new() -> Scope { // Graphics. std.def_node::<graphics::ImageNode>("image"); + std.def_node::<graphics::LineNode>("line"); std.def_node::<graphics::RectNode>("rect"); std.def_node::<graphics::SquareNode>("square"); std.def_node::<graphics::EllipseNode>("ellipse"); @@ -170,3 +171,14 @@ castable! { Expected: "content", Value::Content(content) => content.pack(), } + +castable! { + Spec<Linear>, + Expected: "two-dimensional length array", + Value::Array(array) => { + let e = "point array must contain exactly two entries"; + let a = array.get(0).map_err(|_| e)?.clone().cast::<Linear>()?; + let b = array.get(1).map_err(|_| e)?.clone().cast::<Linear>()?; + Spec::new(a, b) + }, +} |
