summaryrefslogtreecommitdiff
path: root/src/geom/stroke.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-06-06 21:13:59 +0200
committerLaurenz <laurmaedje@gmail.com>2023-06-06 22:06:16 +0200
commitfd417da04f7ca4b995de7f6510abafd3e9c31307 (patch)
tree3675529c75ca7363701ac8ea306de2cc1d3cbcb3 /src/geom/stroke.rs
parent168bdf35bd773e67343c965cb473492cc5cae9e7 (diff)
Improve value casting infrastructure
Diffstat (limited to 'src/geom/stroke.rs')
-rw-r--r--src/geom/stroke.rs224
1 files changed, 111 insertions, 113 deletions
diff --git a/src/geom/stroke.rs b/src/geom/stroke.rs
index 6539922c..66264d5d 100644
--- a/src/geom/stroke.rs
+++ b/src/geom/stroke.rs
@@ -1,3 +1,5 @@
+use crate::eval::{Cast, FromValue};
+
use super::*;
/// A stroke of a geometric shape.
@@ -169,8 +171,78 @@ impl<T: Debug> Debug for PartialStroke<T> {
}
}
+impl Resolve for PartialStroke {
+ type Output = PartialStroke<Abs>;
+
+ fn resolve(self, styles: StyleChain) -> Self::Output {
+ PartialStroke {
+ paint: self.paint,
+ thickness: self.thickness.resolve(styles),
+ line_cap: self.line_cap,
+ line_join: self.line_join,
+ dash_pattern: self.dash_pattern.resolve(styles),
+ miter_limit: self.miter_limit,
+ }
+ }
+}
+
+impl Fold for PartialStroke<Abs> {
+ type Output = Self;
+
+ fn fold(self, outer: Self::Output) -> Self::Output {
+ Self {
+ paint: self.paint.or(outer.paint),
+ thickness: self.thickness.or(outer.thickness),
+ line_cap: self.line_cap.or(outer.line_cap),
+ line_join: self.line_join.or(outer.line_join),
+ dash_pattern: self.dash_pattern.or(outer.dash_pattern),
+ miter_limit: self.miter_limit.or(outer.miter_limit),
+ }
+ }
+}
+
+cast! {
+ type PartialStroke: "stroke",
+ thickness: Length => Self {
+ thickness: Smart::Custom(thickness),
+ ..Default::default()
+ },
+ color: Color => Self {
+ paint: Smart::Custom(color.into()),
+ ..Default::default()
+ },
+ mut dict: Dict => {
+ fn take<T: FromValue>(dict: &mut Dict, key: &str) -> StrResult<Smart<T>> {
+ Ok(dict.take(key).ok().map(T::from_value)
+ .transpose()?.map(Smart::Custom).unwrap_or(Smart::Auto))
+ }
+
+ let paint = take::<Paint>(&mut dict, "paint")?;
+ let thickness = take::<Length>(&mut dict, "thickness")?;
+ let line_cap = take::<LineCap>(&mut dict, "cap")?;
+ let line_join = take::<LineJoin>(&mut dict, "join")?;
+ let dash_pattern = take::<Option<DashPattern>>(&mut dict, "dash")?;
+ let miter_limit = take::<f64>(&mut dict, "miter-limit")?;
+ dict.finish(&["paint", "thickness", "cap", "join", "dash", "miter-limit"])?;
+
+ Self {
+ paint,
+ thickness,
+ line_cap,
+ line_join,
+ dash_pattern,
+ miter_limit: miter_limit.map(Scalar),
+ }
+ },
+}
+
+cast! {
+ PartialStroke<Abs>,
+ self => self.map(Length::from).into_value(),
+}
+
/// The line cap of a stroke
-#[derive(Cast, Clone, Eq, PartialEq, Hash)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Cast)]
pub enum LineCap {
Butt,
Round,
@@ -188,7 +260,7 @@ impl Debug for LineCap {
}
/// The line join of a stroke
-#[derive(Cast, Clone, Eq, PartialEq, Hash)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Cast)]
pub enum LineJoin {
Miter,
Round,
@@ -235,49 +307,22 @@ impl<T: Default> From<Vec<DashLength<T>>> for DashPattern<T> {
}
}
-/// The length of a dash in a line dash pattern
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub enum DashLength<T = Length> {
- LineWidth,
- Length(T),
-}
-
-impl From<Abs> for DashLength {
- fn from(l: Abs) -> Self {
- DashLength::Length(l.into())
- }
-}
-
-impl<T> DashLength<T> {
- fn finish(self, line_width: T) -> T {
- match self {
- Self::LineWidth => line_width,
- Self::Length(l) => l,
- }
- }
-}
-
-cast_from_value! {
- DashLength: "dash length",
- "dot" => Self::LineWidth,
- l: Length => Self::Length(l),
-}
-
-impl Resolve for DashLength {
- type Output = DashLength<Abs>;
+impl Resolve for DashPattern {
+ type Output = DashPattern<Abs>;
fn resolve(self, styles: StyleChain) -> Self::Output {
- match self {
- Self::LineWidth => DashLength::LineWidth,
- Self::Length(l) => DashLength::Length(l.resolve(styles)),
+ DashPattern {
+ array: self.array.into_iter().map(|l| l.resolve(styles)).collect(),
+ phase: self.phase.resolve(styles),
}
}
}
-cast_from_value! {
- DashPattern: "dash pattern",
- // Use same names as tikz:
- // https://tex.stackexchange.com/questions/45275/tikz-get-values-for-predefined-dash-patterns
+// Same names as tikz:
+// https://tex.stackexchange.com/questions/45275/tikz-get-values-for-predefined-dash-patterns
+cast! {
+ DashPattern,
+
"solid" => Vec::new().into(),
"dotted" => vec![DashLength::LineWidth, Abs::pt(2.0).into()].into(),
"densely-dotted" => vec![DashLength::LineWidth, Abs::pt(1.0).into()].into(),
@@ -288,19 +333,13 @@ cast_from_value! {
"dash-dotted" => vec![Abs::pt(3.0).into(), Abs::pt(2.0).into(), DashLength::LineWidth, Abs::pt(2.0).into()].into(),
"densely-dash-dotted" => vec![Abs::pt(3.0).into(), Abs::pt(1.0).into(), DashLength::LineWidth, Abs::pt(1.0).into()].into(),
"loosely-dash-dotted" => vec![Abs::pt(3.0).into(), Abs::pt(4.0).into(), DashLength::LineWidth, Abs::pt(4.0).into()].into(),
- array: Vec<DashLength> => {
- Self {
- array,
- phase: Length::zero(),
- }
- },
+
+ array: Vec<DashLength> => Self { array, phase: Length::zero() },
mut dict: Dict => {
let array: Vec<DashLength> = dict.take("array")?.cast()?;
- let phase = dict.take("phase").ok().map(Length::cast)
+ let phase = dict.take("phase").ok().map(Value::cast)
.transpose()?.unwrap_or(Length::zero());
-
dict.finish(&["array", "phase"])?;
-
Self {
array,
phase,
@@ -308,82 +347,41 @@ cast_from_value! {
},
}
-impl Resolve for DashPattern {
- type Output = DashPattern<Abs>;
-
- fn resolve(self, styles: StyleChain) -> Self::Output {
- DashPattern {
- array: self.array.into_iter().map(|l| l.resolve(styles)).collect(),
- phase: self.phase.resolve(styles),
- }
- }
+/// The length of a dash in a line dash pattern
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub enum DashLength<T = Length> {
+ LineWidth,
+ Length(T),
}
-cast_from_value! {
- PartialStroke: "stroke",
- thickness: Length => Self {
- thickness: Smart::Custom(thickness),
- ..Default::default()
- },
- color: Color => Self {
- paint: Smart::Custom(color.into()),
- ..Default::default()
- },
- mut dict: Dict => {
- fn take<T: Cast<Value>>(dict: &mut Dict, key: &str) -> StrResult<Smart<T>> {
- Ok(dict.take(key).ok().map(T::cast)
- .transpose()?.map(Smart::Custom).unwrap_or(Smart::Auto))
- }
-
- let paint = take::<Paint>(&mut dict, "paint")?;
- let thickness = take::<Length>(&mut dict, "thickness")?;
- let line_cap = take::<LineCap>(&mut dict, "cap")?;
- let line_join = take::<LineJoin>(&mut dict, "join")?;
- let dash_pattern = take::<Option<DashPattern>>(&mut dict, "dash")?;
- let miter_limit = take::<f64>(&mut dict, "miter-limit")?;
- dict.finish(&["paint", "thickness", "cap", "join", "dash", "miter-limit"])?;
-
- Self {
- paint,
- thickness,
- line_cap,
- line_join,
- dash_pattern,
- miter_limit: miter_limit.map(Scalar),
- }
- },
+impl From<Abs> for DashLength {
+ fn from(l: Abs) -> Self {
+ DashLength::Length(l.into())
+ }
}
-impl Resolve for PartialStroke {
- type Output = PartialStroke<Abs>;
-
- fn resolve(self, styles: StyleChain) -> Self::Output {
- PartialStroke {
- paint: self.paint,
- thickness: self.thickness.resolve(styles),
- line_cap: self.line_cap,
- line_join: self.line_join,
- dash_pattern: self.dash_pattern.resolve(styles),
- miter_limit: self.miter_limit,
+impl<T> DashLength<T> {
+ fn finish(self, line_width: T) -> T {
+ match self {
+ Self::LineWidth => line_width,
+ Self::Length(l) => l,
}
}
}
-impl Fold for PartialStroke<Abs> {
- type Output = Self;
+impl Resolve for DashLength {
+ type Output = DashLength<Abs>;
- fn fold(self, outer: Self::Output) -> Self::Output {
- Self {
- paint: self.paint.or(outer.paint),
- thickness: self.thickness.or(outer.thickness),
- line_cap: self.line_cap.or(outer.line_cap),
- line_join: self.line_join.or(outer.line_join),
- dash_pattern: self.dash_pattern.or(outer.dash_pattern),
- miter_limit: self.miter_limit.or(outer.miter_limit),
+ fn resolve(self, styles: StyleChain) -> Self::Output {
+ match self {
+ Self::LineWidth => DashLength::LineWidth,
+ Self::Length(v) => DashLength::Length(v.resolve(styles)),
}
}
}
-cast_to_value! {
- v: PartialStroke<Abs> => v.map(Length::from).into()
+cast! {
+ DashLength,
+ "dot" => Self::LineWidth,
+ v: Length => Self::Length(v),
}