summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-11-20 15:51:07 +0100
committerLaurenz <laurmaedje@gmail.com>2021-11-20 15:51:07 +0100
commitcef46e6c40fed0089a20e44ff2f251c06878891c (patch)
treea4f12ced1441a014f0446f5b01e3f0f87bdd21b5 /src/library
parent70c0dd767452772d29167e39b1c4f919519422ce (diff)
Strokes
Diffstat (limited to 'src/library')
-rw-r--r--src/library/deco.rs27
-rw-r--r--src/library/page.rs8
-rw-r--r--src/library/shape.rs76
-rw-r--r--src/library/text.rs32
-rw-r--r--src/library/utility.rs4
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.