summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Haug <mhaug@live.de>2022-03-16 12:36:50 +0100
committerMartin Haug <mhaug@live.de>2022-03-16 12:36:50 +0100
commit4d617bcd67f9e42218da190dc9a0bf2f10d4b78d (patch)
treefea275e9321004c15ed7d1def9f3749641f648ed /src
parent288a926feae1e73dff5a6b103aa920d6f7eb0f35 (diff)
`LineNode`
Diffstat (limited to 'src')
-rw-r--r--src/geom/angle.rs10
-rw-r--r--src/geom/point.rs6
-rw-r--r--src/library/graphics/line.rs61
-rw-r--r--src/library/graphics/mod.rs2
-rw-r--r--src/library/mod.rs12
5 files changed, 91 insertions, 0 deletions
diff --git a/src/geom/angle.rs b/src/geom/angle.rs
index ef3276e8..4e08a518 100644
--- a/src/geom/angle.rs
+++ b/src/geom/angle.rs
@@ -40,6 +40,16 @@ impl Angle {
(self.0).0
}
+ /// Get the sine of this angle.
+ pub fn sin(self) -> f64 {
+ self.to_rad().sin()
+ }
+
+ /// Get the cosine of this angle.
+ pub fn cos(self) -> f64 {
+ self.to_rad().cos()
+ }
+
/// Create an angle from a value in a unit.
pub fn with_unit(val: f64, unit: AngularUnit) -> Self {
Self(Scalar(val * unit.raw_scale()))
diff --git a/src/geom/point.rs b/src/geom/point.rs
index 6d77507b..7ab0d375 100644
--- a/src/geom/point.rs
+++ b/src/geom/point.rs
@@ -49,6 +49,12 @@ impl Point {
}
}
+impl From<Spec<Length>> for Point {
+ fn from(spec: Spec<Length>) -> Self {
+ Self::new(spec.x, spec.y)
+ }
+}
+
impl Get<SpecAxis> for Point {
type Component = Length;
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)
+ },
+}