diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-11-20 15:51:07 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-11-20 15:51:07 +0100 |
| commit | cef46e6c40fed0089a20e44ff2f251c06878891c (patch) | |
| tree | a4f12ced1441a014f0446f5b01e3f0f87bdd21b5 /src/library | |
| parent | 70c0dd767452772d29167e39b1c4f919519422ce (diff) | |
Strokes
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/deco.rs | 27 | ||||
| -rw-r--r-- | src/library/page.rs | 8 | ||||
| -rw-r--r-- | src/library/shape.rs | 76 | ||||
| -rw-r--r-- | src/library/text.rs | 32 | ||||
| -rw-r--r-- | src/library/utility.rs | 4 |
5 files changed, 71 insertions, 76 deletions
diff --git a/src/library/deco.rs b/src/library/deco.rs index 2722fd68..1f8c051f 100644 --- a/src/library/deco.rs +++ b/src/library/deco.rs @@ -17,20 +17,13 @@ pub fn overline(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } fn line_impl(args: &mut Args, kind: LineKind) -> TypResult<Value> { - let stroke = args.named("stroke")?.or_else(|| args.find()); + let stroke = args.named("stroke")?.or_else(|| args.find()).map(Paint::Solid); let thickness = args.named::<Linear>("thickness")?.or_else(|| args.find()); let offset = args.named("offset")?; let extent = args.named("extent")?.unwrap_or_default(); let body: Template = args.expect("body")?; - Ok(Value::Template(body.decorate(Decoration::Line( - LineDecoration { - kind, - stroke: stroke.map(Paint::Color), - thickness, - offset, - extent, - }, + LineDecoration { kind, stroke, thickness, offset, extent }, )))) } @@ -112,12 +105,15 @@ impl LineDecoration { LineKind::Overline => face.overline, }; - let stroke = self.stroke.unwrap_or(text.fill); - let thickness = self .thickness .map(|s| s.resolve(text.size)) - .unwrap_or(metrics.strength.to_length(text.size)); + .unwrap_or(metrics.thickness.to_length(text.size)); + + let stroke = Stroke { + paint: self.stroke.unwrap_or(text.fill), + thickness, + }; let offset = self .offset @@ -127,10 +123,9 @@ impl LineDecoration { let extent = self.extent.resolve(text.size); let subpos = Point::new(pos.x - extent, pos.y + offset); - let vector = Point::new(text.width + 2.0 * extent, Length::zero()); - let line = Geometry::Line(vector, thickness); - - frame.push(subpos, Element::Geometry(line, stroke)); + let target = Point::new(text.width + 2.0 * extent, Length::zero()); + let shape = Shape::stroked(Geometry::Line(target), stroke); + frame.push(subpos, Element::Shape(shape)); } } } diff --git a/src/library/page.rs b/src/library/page.rs index b760e76a..20871bd9 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -18,7 +18,7 @@ pub fn page(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let right = args.named("right")?; let bottom = args.named("bottom")?; let flip = args.named("flip")?; - let fill = args.named("fill")?; + let fill = args.named("fill")?.map(Paint::Solid); ctx.template.modify(move |style| { let page = style.page_mut(); @@ -63,7 +63,7 @@ pub fn page(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } if let Some(fill) = fill { - page.fill = Some(Paint::Color(fill)); + page.fill = Some(fill); } }); @@ -105,8 +105,8 @@ impl PageNode { // Add background fill if requested. if let Some(fill) = self.fill { for frame in &mut frames { - let element = Element::Geometry(Geometry::Rect(frame.size), fill); - Rc::make_mut(frame).prepend(Point::zero(), element); + let shape = Shape::filled(Geometry::Rect(frame.size), fill); + Rc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape)); } } diff --git a/src/library/shape.rs b/src/library/shape.rs index d0df5f48..abf927e4 100644 --- a/src/library/shape.rs +++ b/src/library/shape.rs @@ -7,9 +7,7 @@ use crate::util::RcExt; pub fn rect(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let width = args.named("width")?; let height = args.named("height")?; - let fill = args.named("fill")?; - let body = args.find(); - Ok(shape_impl(ShapeKind::Rect, width, height, fill, body)) + shape_impl(args, ShapeKind::Rect, width, height) } /// `square`: A square with optional content. @@ -23,18 +21,14 @@ pub fn square(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { None => args.named("height")?, size => size, }; - let fill = args.named("fill")?; - let body = args.find(); - Ok(shape_impl(ShapeKind::Square, width, height, fill, body)) + shape_impl(args, ShapeKind::Square, width, height) } /// `ellipse`: An ellipse with optional content. pub fn ellipse(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let width = args.named("width")?; let height = args.named("height")?; - let fill = args.named("fill")?; - let body = args.find(); - Ok(shape_impl(ShapeKind::Ellipse, width, height, fill, body)) + shape_impl(args, ShapeKind::Ellipse, width, height) } /// `circle`: A circle with optional content. @@ -48,30 +42,44 @@ pub fn circle(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { None => args.named("height")?, diameter => diameter, }; - let fill = args.named("fill")?; - let body = args.find(); - Ok(shape_impl(ShapeKind::Circle, width, height, fill, body)) + shape_impl(args, ShapeKind::Circle, width, height) } fn shape_impl( + args: &mut Args, kind: ShapeKind, width: Option<Linear>, height: Option<Linear>, - fill: Option<Color>, - body: Option<Template>, -) -> Value { - // Set default fill if there's no fill. - let fill = fill.unwrap_or(Color::Rgba(RgbaColor::gray(175))); +) -> TypResult<Value> { + // The default appearance of a shape. + let default = Stroke { + paint: RgbaColor::BLACK.into(), + thickness: Length::pt(1.0), + }; + + // Parse fill & stroke. + let fill = args.named("fill")?.map(Paint::Solid); + let stroke = match (args.named("stroke")?, args.named("thickness")?) { + (None, None) => fill.is_none().then(|| default), + (color, thickness) => Some(Stroke { + paint: color.map(Paint::Solid).unwrap_or(default.paint), + thickness: thickness.unwrap_or(default.thickness), + }), + }; - Value::Template(Template::from_inline(move |style| { + let padding = Sides::splat(args.named("padding")?.unwrap_or_default()); + let body = args.find::<Template>(); + + Ok(Value::Template(Template::from_inline(move |style| { ShapeNode { kind, - fill: Some(Paint::Color(fill)), - child: body.as_ref().map(|body| body.pack(style)), + fill, + stroke, + child: body.as_ref().map(|body| body.pack(style).padded(padding)), } .pack() .sized(width, height) - })) + }))) } /// Places its child into a sizable and fillable shape. @@ -79,8 +87,10 @@ fn shape_impl( pub struct ShapeNode { /// Which shape to place the child into. pub kind: ShapeKind, - /// How to fill the shape, if at all. + /// How to fill the shape. pub fill: Option<Paint>, + /// How the stroke the shape. + pub stroke: Option<Stroke>, /// The child node to place into the shape, if any. pub child: Option<PackedNode>, } @@ -160,18 +170,20 @@ impl Layout for ShapeNode { Frame::new(size, size.h) }; - // Add background fill if desired. - if let Some(fill) = self.fill { - let (pos, geometry) = match self.kind { - ShapeKind::Square | ShapeKind::Rect => { - (Point::zero(), Geometry::Rect(frame.size)) - } - ShapeKind::Circle | ShapeKind::Ellipse => { - (frame.size.to_point() / 2.0, Geometry::Ellipse(frame.size)) - } + // Add fill and/or stroke. + if self.fill.is_some() || self.stroke.is_some() { + let geometry = match self.kind { + ShapeKind::Square | ShapeKind::Rect => Geometry::Rect(frame.size), + ShapeKind::Circle | ShapeKind::Ellipse => Geometry::Ellipse(frame.size), + }; + + let shape = Shape { + geometry, + fill: self.fill, + stroke: self.stroke, }; - frame.prepend(pos, Element::Geometry(geometry, fill)); + frame.prepend(Point::zero(), Element::Shape(shape)); } // Ensure frame size matches regions size if expansion is on. diff --git a/src/library/text.rs b/src/library/text.rs index cdcc7509..d0b5c8e6 100644 --- a/src/library/text.rs +++ b/src/library/text.rs @@ -163,12 +163,12 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let fallback = args.named("fallback")?; let style = args.named("style")?; let weight = args.named("weight")?; - let tracking = args.named("tracking")?; let stretch = args.named("stretch")?; let size = args.named::<Linear>("size")?.or_else(|| args.find()); + let tracking = args.named("tracking")?.map(Em::new); let top_edge = args.named("top-edge")?; let bottom_edge = args.named("bottom-edge")?; - let fill = args.named("fill")?.or_else(|| args.find()); + let fill = args.named("fill")?.or_else(|| args.find()).map(Paint::Solid); let kerning = args.named("kerning")?; let smallcaps = args.named("smallcaps")?; let alternates = args.named("alternates")?; @@ -182,7 +182,6 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let slashed_zero = args.named("slashed-zero")?; let fractions = args.named("fractions")?; let features = args.named("features")?; - let body = args.find::<Template>(); macro_rules! set { @@ -195,30 +194,19 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let f = move |style_: &mut Style| { let text = style_.text_mut(); - - if let Some(size) = size { - text.size = size.resolve(text.size); - } - - if let Some(fill) = fill { - text.fill = Paint::Color(fill); - } - - if let Some(tracking) = tracking { - text.tracking = Em::new(tracking); - } - + set!(text.families_mut().list => list.clone()); + set!(text.families_mut().serif => serif.clone()); + set!(text.families_mut().sans_serif => sans_serif.clone()); + set!(text.families_mut().monospace => monospace.clone()); + set!(text.fallback => fallback); set!(text.variant.style => style); set!(text.variant.weight => weight); set!(text.variant.stretch => stretch); + set!(text.size => size.map(|v| v.resolve(text.size))); + set!(text.tracking => tracking); set!(text.top_edge => top_edge); set!(text.bottom_edge => bottom_edge); - set!(text.fallback => fallback); - - set!(text.families_mut().list => list.clone()); - set!(text.families_mut().serif => serif.clone()); - set!(text.families_mut().sans_serif => sans_serif.clone()); - set!(text.families_mut().monospace => monospace.clone()); + set!(text.fill => fill); set!(text.features_mut().kerning => kerning); set!(text.features_mut().smallcaps => smallcaps); set!(text.features_mut().alternates => alternates); diff --git a/src/library/utility.rs b/src/library/utility.rs index 6d15a823..b2435e8a 100644 --- a/src/library/utility.rs +++ b/src/library/utility.rs @@ -86,7 +86,7 @@ pub fn str(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { /// `rgb`: Create an RGB(A) color. pub fn rgb(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - Ok(Value::Color(Color::Rgba( + Ok(Value::from( if let Some(string) = args.find::<Spanned<EcoString>>() { match RgbaColor::from_str(&string.v) { Ok(color) => color, @@ -106,7 +106,7 @@ pub fn rgb(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { }; RgbaColor::new(f(r)?, f(g)?, f(b)?, f(a)?) }, - ))) + )) } /// `abs`: The absolute value of a numeric value. |
