From 7a6c2cce7747f7632f0be012f49b548db3e62a2d Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 14 Jun 2022 15:07:13 +0200 Subject: [PATCH] Make radius configuration unconfusing --- src/eval/dict.rs | 5 + src/eval/value.rs | 210 ++++++++++++++++++------------ src/geom/corners.rs | 122 +++++++++++++++++ src/geom/mod.rs | 2 + src/geom/rect.rs | 44 +++---- src/geom/sides.rs | 27 +++- src/library/graphics/shape.rs | 4 +- src/model/property.rs | 42 ++++-- tests/ref/graphics/shape-rect.png | Bin 16279 -> 16266 bytes tests/typ/graphics/shape-rect.typ | 17 ++- 10 files changed, 346 insertions(+), 127 deletions(-) create mode 100644 src/geom/corners.rs diff --git a/src/eval/dict.rs b/src/eval/dict.rs index 8893ce483..654c90eb5 100644 --- a/src/eval/dict.rs +++ b/src/eval/dict.rs @@ -76,6 +76,11 @@ impl Dict { } } + /// Remove the value if the dictionary contains the given key. + pub fn take(&mut self, key: &str) -> Option { + Arc::make_mut(&mut self.0).remove(key) + } + /// Clear the dictionary. pub fn clear(&mut self) { if Arc::strong_count(&self.0) == 1 { diff --git a/src/eval/value.rs b/src/eval/value.rs index a7da99c92..294aac946 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -8,7 +8,8 @@ use std::sync::Arc; use super::{ops, Args, Array, Dict, Func, RawLength, Regex}; use crate::diag::{with_alternative, StrResult}; use crate::geom::{ - Angle, Color, Dir, Em, Fraction, Length, Paint, Ratio, Relative, RgbaColor, Sides, + Angle, Color, Corners, Dir, Em, Fraction, Length, Paint, Ratio, Relative, RgbaColor, + Sides, }; use crate::library::text::RawNode; use crate::model::{Content, Group, Layout, LayoutNode, Pattern}; @@ -516,6 +517,71 @@ impl Cast> for Spanned { } } +dynamic! { + Dir: "direction", +} + +dynamic! { + Regex: "regular expression", +} + +dynamic! { + Group: "group", +} + +castable! { + usize, + Expected: "non-negative integer", + Value::Int(int) => int.try_into().map_err(|_| { + if int < 0 { + "must be at least zero" + } else { + "number too large" + } + })?, +} + +castable! { + NonZeroUsize, + Expected: "positive integer", + Value::Int(int) => int + .try_into() + .and_then(|int: usize| int.try_into()) + .map_err(|_| if int <= 0 { + "must be positive" + } else { + "number too large" + })?, +} + +castable! { + Paint, + Expected: "color", + Value::Color(color) => Paint::Solid(color), +} + +castable! { + String, + Expected: "string", + Value::Str(string) => string.into(), +} + +castable! { + LayoutNode, + Expected: "content", + Value::None => Self::default(), + Value::Str(text) => Content::Text(text).pack(), + Value::Content(content) => content.pack(), +} + +castable! { + Pattern, + Expected: "function, string or regular expression", + Value::Func(func) => Self::Node(func.node()?), + Value::Str(text) => Self::text(&text), + @regex: Regex => Self::Regex(regex.clone()), +} + impl Cast for Option { fn is(value: &Value) -> bool { matches!(value, Value::None) || T::is(value) @@ -609,112 +675,84 @@ impl Cast for Smart { impl Cast for Sides where - T: Cast + Default + Clone, + T: Cast + Default + Copy, { fn is(value: &Value) -> bool { matches!(value, Value::Dict(_)) || T::is(value) } - fn cast(value: Value) -> StrResult { - match value { - Value::Dict(dict) => { - for (key, _) in &dict { - if !matches!( - key.as_str(), - "left" | "top" | "right" | "bottom" | "x" | "y" | "rest" - ) { - return Err(format!("unexpected key {key:?}")); - } - } + fn cast(mut value: Value) -> StrResult { + if let Value::Dict(dict) = &mut value { + let mut take = |key| dict.take(key).map(T::cast).transpose(); - let sides = Sides { - left: dict.get("left").or(dict.get("x")), - top: dict.get("top").or(dict.get("y")), - right: dict.get("right").or(dict.get("x")), - bottom: dict.get("bottom").or(dict.get("y")), - }; + let rest = take("rest")?; + let x = take("x")?.or(rest); + let y = take("y")?.or(rest); + let sides = Sides { + left: take("left")?.or(x), + top: take("top")?.or(y), + right: take("right")?.or(x), + bottom: take("bottom")?.or(y), + }; - Ok(sides.map(|side| { - side.or(dict.get("rest")) - .cloned() - .and_then(T::cast) - .unwrap_or_default() - })) + if let Some((key, _)) = dict.iter().next() { + return Err(format!("unexpected key {key:?}")); } - v => T::cast(v).map(Sides::splat).map_err(|msg| { + + Ok(sides.map(Option::unwrap_or_default)) + } else { + T::cast(value).map(Self::splat).map_err(|msg| { with_alternative( msg, - "dictionary with any of `left`, `top`, `right`, `bottom`, \ + "dictionary with any of \ + `left`, `top`, `right`, `bottom`, \ `x`, `y`, or `rest` as keys", ) - }), + }) } } } -dynamic! { - Dir: "direction", -} +impl Cast for Corners +where + T: Cast + Default + Copy, +{ + fn is(value: &Value) -> bool { + matches!(value, Value::Dict(_)) || T::is(value) + } -dynamic! { - Regex: "regular expression", -} + fn cast(mut value: Value) -> StrResult { + if let Value::Dict(dict) = &mut value { + let mut take = |key| dict.take(key).map(T::cast).transpose(); -dynamic! { - Group: "group", -} + let rest = take("rest")?; + let left = take("left")?.or(rest); + let top = take("top")?.or(rest); + let right = take("right")?.or(rest); + let bottom = take("bottom")?.or(rest); + let corners = Corners { + top_left: take("top-left")?.or(top).or(left), + top_right: take("top-right")?.or(top).or(right), + bottom_right: take("bottom-right")?.or(bottom).or(right), + bottom_left: take("bottom-left")?.or(bottom).or(left), + }; -castable! { - usize, - Expected: "non-negative integer", - Value::Int(int) => int.try_into().map_err(|_| { - if int < 0 { - "must be at least zero" + if let Some((key, _)) = dict.iter().next() { + return Err(format!("unexpected key {key:?}")); + } + + Ok(corners.map(Option::unwrap_or_default)) } else { - "number too large" + T::cast(value).map(Self::splat).map_err(|msg| { + with_alternative( + msg, + "dictionary with any of \ + `top-left`, `top-right`, `bottom-right`, `bottom-left`, \ + `left`, `top`, `right`, `bottom`, or `rest` as keys", + ) + }) } - })?, -} - -castable! { - NonZeroUsize, - Expected: "positive integer", - Value::Int(int) => int - .try_into() - .and_then(|int: usize| int.try_into()) - .map_err(|_| if int <= 0 { - "must be positive" - } else { - "number too large" - })?, -} - -castable! { - Paint, - Expected: "color", - Value::Color(color) => Paint::Solid(color), -} - -castable! { - String, - Expected: "string", - Value::Str(string) => string.into(), -} - -castable! { - LayoutNode, - Expected: "content", - Value::None => Self::default(), - Value::Str(text) => Content::Text(text).pack(), - Value::Content(content) => content.pack(), -} - -castable! { - Pattern, - Expected: "function, string or regular expression", - Value::Func(func) => Self::Node(func.node()?), - Value::Str(text) => Self::text(&text), - @regex: Regex => Self::Regex(regex.clone()), + } } #[cfg(test)] diff --git a/src/geom/corners.rs b/src/geom/corners.rs new file mode 100644 index 000000000..54fcd12f3 --- /dev/null +++ b/src/geom/corners.rs @@ -0,0 +1,122 @@ +use super::*; + +/// A container with components for the four corners of a rectangle. +#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)] +pub struct Corners { + /// The value for the top left corner. + pub top_left: T, + /// The value for the top right corner. + pub top_right: T, + /// The value for the bottom right corner. + pub bottom_right: T, + /// The value for the bottom left corner. + pub bottom_left: T, +} + +impl Corners { + /// Create a new instance from the four components. + pub const fn new(top_left: T, top_right: T, bottom_right: T, bottom_left: T) -> Self { + Self { + top_left, + top_right, + bottom_right, + bottom_left, + } + } + + /// Create an instance with four equal components. + pub fn splat(value: T) -> Self + where + T: Clone, + { + Self { + top_left: value.clone(), + top_right: value.clone(), + bottom_right: value.clone(), + bottom_left: value, + } + } + + /// Map the individual fields with `f`. + pub fn map(self, mut f: F) -> Corners + where + F: FnMut(T) -> U, + { + Corners { + top_left: f(self.top_left), + top_right: f(self.top_right), + bottom_right: f(self.bottom_right), + bottom_left: f(self.bottom_left), + } + } + + /// Zip two instances into an instance. + pub fn zip(self, other: Corners, mut f: F) -> Corners + where + F: FnMut(T, V) -> W, + { + Corners { + top_left: f(self.top_left, other.top_left), + top_right: f(self.top_right, other.top_right), + bottom_right: f(self.bottom_right, other.bottom_right), + bottom_left: f(self.bottom_left, other.bottom_left), + } + } + + /// An iterator over the corners, starting with the top left corner, + /// clockwise. + pub fn iter(&self) -> impl Iterator { + [ + &self.top_left, + &self.top_right, + &self.bottom_right, + &self.bottom_left, + ] + .into_iter() + } + + /// Whether all sides are equal. + pub fn is_uniform(&self) -> bool + where + T: PartialEq, + { + self.top_left == self.top_right + && self.top_right == self.bottom_right + && self.bottom_right == self.bottom_left + } +} + +impl Get for Corners { + type Component = T; + + fn get(self, corner: Corner) -> T { + match corner { + Corner::TopLeft => self.top_left, + Corner::TopRight => self.top_right, + Corner::BottomRight => self.bottom_right, + Corner::BottomLeft => self.bottom_left, + } + } + + fn get_mut(&mut self, corner: Corner) -> &mut T { + match corner { + Corner::TopLeft => &mut self.top_left, + Corner::TopRight => &mut self.top_right, + Corner::BottomRight => &mut self.bottom_right, + Corner::BottomLeft => &mut self.bottom_left, + } + } +} + +/// The four corners of a rectangle. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum Corner { + /// The top left corner. + TopLeft, + /// The top right corner. + TopRight, + /// The bottom right corner. + BottomRight, + /// The bottom left corner. + BottomLeft, +} diff --git a/src/geom/mod.rs b/src/geom/mod.rs index bdd08fe5a..fc8ccb6c0 100644 --- a/src/geom/mod.rs +++ b/src/geom/mod.rs @@ -4,6 +4,7 @@ mod macros; mod align; mod angle; +mod corners; mod dir; mod em; mod fraction; @@ -22,6 +23,7 @@ mod transform; pub use align::*; pub use angle::*; +pub use corners::*; pub use dir::*; pub use em::*; pub use fraction::*; diff --git a/src/geom/rect.rs b/src/geom/rect.rs index dceb35777..dfea2c452 100644 --- a/src/geom/rect.rs +++ b/src/geom/rect.rs @@ -7,13 +7,13 @@ use std::mem; pub struct RoundedRect { /// The size of the rectangle. pub size: Size, - /// The radius at each side. - pub radius: Sides, + /// The radius at each corner. + pub radius: Corners, } impl RoundedRect { /// Create a new rounded rectangle. - pub fn new(size: Size, radius: Sides) -> Self { + pub fn new(size: Size, radius: Corners) -> Self { Self { size, radius } } @@ -73,20 +73,20 @@ impl RoundedRect { let mut always_continuous = true; for side in [Side::Top, Side::Right, Side::Bottom, Side::Left] { - let is_continuous = strokes.get(side) == strokes.get(side.next_cw()); - connection = connection.advance(is_continuous && side != Side::Left); - always_continuous &= is_continuous; + let continuous = strokes.get(side) == strokes.get(side.next_cw()); + connection = connection.advance(continuous && side != Side::Left); + always_continuous &= continuous; draw_side( &mut path, side, self.size, - self.radius.get(side.next_ccw()), - self.radius.get(side), + self.radius.get(side.start_corner()), + self.radius.get(side.end_corner()), connection, ); - if !is_continuous { + if !continuous { res.push((mem::take(&mut path), strokes.get(side))); } } @@ -109,8 +109,8 @@ fn draw_side( path: &mut Path, side: Side, size: Size, - radius_left: Length, - radius_right: Length, + start_radius: Length, + end_radius: Length, connection: Connection, ) { let angle_left = Angle::deg(if connection.prev { 90.0 } else { 45.0 }); @@ -118,23 +118,23 @@ fn draw_side( let length = size.get(side.axis()); // The arcs for a border of the rectangle along the x-axis, starting at (0,0). - let p1 = Point::with_x(radius_left); + let p1 = Point::with_x(start_radius); let mut arc1 = bezier_arc( p1 + Point::new( - -angle_left.sin() * radius_left, - (1.0 - angle_left.cos()) * radius_left, + -angle_left.sin() * start_radius, + (1.0 - angle_left.cos()) * start_radius, ), - Point::new(radius_left, radius_left), + Point::new(start_radius, start_radius), p1, ); - let p2 = Point::with_x(length - radius_right); + let p2 = Point::with_x(length - end_radius); let mut arc2 = bezier_arc( p2, - Point::new(length - radius_right, radius_right), + Point::new(length - end_radius, end_radius), p2 + Point::new( - angle_right.sin() * radius_right, - (1.0 - angle_right.cos()) * radius_right, + angle_right.sin() * end_radius, + (1.0 - angle_right.cos()) * end_radius, ), ); @@ -152,16 +152,16 @@ fn draw_side( arc2 = arc2.map(|x| x.transform(transform)); if !connection.prev { - path.move_to(if radius_left.is_zero() { arc1[3] } else { arc1[0] }); + path.move_to(if start_radius.is_zero() { arc1[3] } else { arc1[0] }); } - if !radius_left.is_zero() { + if !start_radius.is_zero() { path.cubic_to(arc1[1], arc1[2], arc1[3]); } path.line_to(arc2[0]); - if !connection.next && !radius_right.is_zero() { + if !connection.next && !end_radius.is_zero() { path.cubic_to(arc2[1], arc2[2], arc2[3]); } } diff --git a/src/geom/sides.rs b/src/geom/sides.rs index 938539fec..727489162 100644 --- a/src/geom/sides.rs +++ b/src/geom/sides.rs @@ -48,17 +48,17 @@ impl Sides { /// Zip two instances into an instance. pub fn zip(self, other: Sides, mut f: F) -> Sides where - F: FnMut(T, V, Side) -> W, + F: FnMut(T, V) -> W, { Sides { - left: f(self.left, other.left, Side::Left), - top: f(self.top, other.top, Side::Top), - right: f(self.right, other.right, Side::Right), - bottom: f(self.bottom, other.bottom, Side::Bottom), + left: f(self.left, other.left), + top: f(self.top, other.top), + right: f(self.right, other.right), + bottom: f(self.bottom, other.bottom), } } - /// An iterator over the sides. + /// An iterator over the sides, starting with the left side, clockwise. pub fn iter(&self) -> impl Iterator { [&self.left, &self.top, &self.right, &self.bottom].into_iter() } @@ -157,6 +157,21 @@ impl Side { } } + /// The first corner of the side in clockwise order. + pub fn start_corner(self) -> Corner { + match self { + Self::Left => Corner::BottomLeft, + Self::Top => Corner::TopLeft, + Self::Right => Corner::TopRight, + Self::Bottom => Corner::BottomRight, + } + } + + /// The second corner of the side in clockwise order. + pub fn end_corner(self) -> Corner { + self.next_cw().start_corner() + } + /// Return the corresponding axis. pub fn axis(self) -> SpecAxis { match self { diff --git a/src/library/graphics/shape.rs b/src/library/graphics/shape.rs index eed3c9d9e..5cc5a76d2 100644 --- a/src/library/graphics/shape.rs +++ b/src/library/graphics/shape.rs @@ -33,9 +33,11 @@ impl ShapeNode { /// How much to extend the shape's dimensions beyond the allocated space. #[property(resolve, fold)] pub const OUTSET: Sides>> = Sides::splat(Relative::zero()); + /// How much to round the shape's corners. #[property(skip, resolve, fold)] - pub const RADIUS: Sides>> = Sides::splat(Relative::zero()); + pub const RADIUS: Corners>> = + Corners::splat(Relative::zero()); fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let size = match S { diff --git a/src/model/property.rs b/src/model/property.rs index 0e171939d..8681da7d5 100644 --- a/src/model/property.rs +++ b/src/model/property.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use super::{Interruption, NodeId, StyleChain}; use crate::eval::{RawLength, Smart}; -use crate::geom::{Length, Numeric, Relative, Sides, Spec}; +use crate::geom::{Corners, Length, Numeric, Relative, Sides, Spec}; use crate::library::layout::PageNode; use crate::library::structure::{EnumNode, ListNode}; use crate::library::text::ParNode; @@ -191,12 +191,15 @@ impl Resolve for Sides { type Output = Sides; fn resolve(self, styles: StyleChain) -> Self::Output { - Sides { - left: self.left.resolve(styles), - right: self.right.resolve(styles), - top: self.top.resolve(styles), - bottom: self.bottom.resolve(styles), - } + self.map(|v| v.resolve(styles)) + } +} + +impl Resolve for Corners { + type Output = Corners; + + fn resolve(self, styles: StyleChain) -> Self::Output { + self.map(|v| v.resolve(styles)) } } @@ -252,7 +255,7 @@ where type Output = Sides; fn fold(self, outer: Self::Output) -> Self::Output { - self.zip(outer, |inner, outer, _| inner.fold(outer)) + self.zip(outer, |inner, outer| inner.fold(outer)) } } @@ -260,7 +263,7 @@ impl Fold for Sides>> { type Output = Sides>; fn fold(self, outer: Self::Output) -> Self::Output { - self.zip(outer, |inner, outer, _| inner.unwrap_or(outer)) + self.zip(outer, |inner, outer| inner.unwrap_or(outer)) } } @@ -268,7 +271,26 @@ impl Fold for Sides>>> { type Output = Sides>>; fn fold(self, outer: Self::Output) -> Self::Output { - self.zip(outer, |inner, outer, _| inner.unwrap_or(outer)) + self.zip(outer, |inner, outer| inner.unwrap_or(outer)) + } +} + +impl Fold for Corners +where + T: Fold, +{ + type Output = Corners; + + fn fold(self, outer: Self::Output) -> Self::Output { + self.zip(outer, |inner, outer| inner.fold(outer)) + } +} + +impl Fold for Corners>> { + type Output = Corners>; + + fn fold(self, outer: Self::Output) -> Self::Output { + self.zip(outer, |inner, outer| inner.unwrap_or(outer)) } } diff --git a/tests/ref/graphics/shape-rect.png b/tests/ref/graphics/shape-rect.png index 2c2c7d7c1d5292f97f9bd61e69ea91860dc3180e..e2ea05029005aa5c12ce2f44b0be69bdc56d74c7 100644 GIT binary patch literal 16266 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 diff --git a/tests/typ/graphics/shape-rect.typ b/tests/typ/graphics/shape-rect.typ index 5495da8c8..7d1101808 100644 --- a/tests/typ/graphics/shape-rect.typ +++ b/tests/typ/graphics/shape-rect.typ @@ -30,8 +30,13 @@ // Rounded corners. #rect(width: 2cm, radius: 60%) -#rect(width: 1cm, radius: (x: 5pt, y: 10pt)) -#rect(width: 1.25cm, radius: (left: 2pt, top: 5pt, right: 8pt, bottom: 11pt)) +#rect(width: 1cm, radius: (left: 10pt, right: 5pt)) +#rect(width: 1.25cm, radius: ( + top-left: 2pt, + top-right: 5pt, + bottom-right: 8pt, + bottom-left: 11pt +)) // Different strokes. [ @@ -54,3 +59,11 @@ Use the `*const T` pointer or the `&mut T` reference. --- // Error: 15-38 unexpected key "cake" #rect(radius: (left: 10pt, cake: 5pt)) + +--- +// Error: 15-21 expected stroke or none or dictionary with any of `left`, `top`, `right`, `bottom`, `x`, `y`, or `rest` as keys or auto, found array +#rect(stroke: (1, 2)) + +--- +// Error: 15-19 expected relative length or none or dictionary with any of `top-left`, `top-right`, `bottom-right`, `bottom-left`, `left`, `top`, `right`, `bottom`, or `rest` as keys, found color +#rect(radius: blue)