summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Haug <mhaug@live.de>2022-05-01 13:21:07 +0200
committerMartin Haug <mhaug@live.de>2022-05-01 14:56:07 +0200
commit84a4961a5dd03072b0e94c715957475d4ae21e4f (patch)
treef23f7b2917943079c12a218de3dd649ef6e590b7
parent5f1499d380e223e7e1b2a8a96eb99e3ec95a56ac (diff)
Outset; fix folding
-rw-r--r--src/frame.rs2
-rw-r--r--src/geom/sides.rs4
-rw-r--r--src/library/graphics/shape.rs90
-rw-r--r--src/model/styles.rs23
-rw-r--r--tests/typ/code/let.typ2
-rw-r--r--tests/typ/code/target.typ2
-rw-r--r--tests/typ/graphics/shape-aspect.typ2
-rw-r--r--tests/typ/graphics/shape-circle.typ4
-rw-r--r--tests/typ/graphics/shape-rect.typ4
-rw-r--r--tests/typ/graphics/shape-square.typ2
-rw-r--r--tests/typ/layout/columns.typ6
-rw-r--r--tests/typ/style/construct.typ6
12 files changed, 93 insertions, 54 deletions
diff --git a/src/frame.rs b/src/frame.rs
index f889601e..2cf584d8 100644
--- a/src/frame.rs
+++ b/src/frame.rs
@@ -478,7 +478,7 @@ pub fn rect_paths(
];
for (side, radius) in sides.into_iter().zip(radius.windows(2)) {
- let stroke_continuity = strokes.get(side) == strokes.get(side.clockwise());
+ let stroke_continuity = strokes.get(side) == strokes.get(side.next_cw());
connection = connection.advance(stroke_continuity && side != Side::Left);
always_continuous &= stroke_continuity;
diff --git a/src/geom/sides.rs b/src/geom/sides.rs
index 255c21ee..f214a1bf 100644
--- a/src/geom/sides.rs
+++ b/src/geom/sides.rs
@@ -128,7 +128,7 @@ impl Side {
}
/// The next side, clockwise.
- pub fn clockwise(self) -> Self {
+ pub fn next_cw(self) -> Self {
match self {
Self::Left => Self::Top,
Self::Top => Self::Right,
@@ -138,7 +138,7 @@ impl Side {
}
/// The next side, counter-clockwise.
- pub fn counter_clockwise(self) -> Self {
+ pub fn next_ccw(self) -> Self {
match self {
Self::Left => Self::Bottom,
Self::Top => Self::Left,
diff --git a/src/library/graphics/shape.rs b/src/library/graphics/shape.rs
index 7a1bfb1f..640c879b 100644
--- a/src/library/graphics/shape.rs
+++ b/src/library/graphics/shape.rs
@@ -102,6 +102,7 @@ castable! {
}
},
Value::Length(l) => Sides::splat(Some(l.into())),
+ Value::Ratio(r) => Sides::splat(Some(r.into())),
Value::Relative(r) => Sides::splat(Some(r)),
}
@@ -117,40 +118,44 @@ impl<const S: ShapeKind> Layout for AngularNode<S> {
let inset = styles.get(Self::INSET);
// Pad the child.
- let child = child
- .clone()
- .padded(inset.map(|side| side.map(|abs| RawLength::from(abs))));
+ let child = child.clone().padded(inset.map(|side| side.map(RawLength::from)));
let mut pod = Regions::one(regions.first, regions.base, regions.expand);
frames = child.layout(ctx, &pod, styles)?;
// Relayout with full expansion into square region to make sure
// the result is really a square or circle.
- let length = if regions.expand.x || regions.expand.y {
- let target = regions.expand.select(regions.first, Size::zero());
- target.x.max(target.y)
- } else {
- let size = frames[0].size;
- let desired = size.x.max(size.y);
- desired.min(regions.first.x).min(regions.first.y)
- };
-
- pod.first = Size::splat(length);
- pod.expand = Spec::splat(true);
- frames = child.layout(ctx, &pod, styles)?;
+ if is_quadratic(S) {
+ let length = if regions.expand.x || regions.expand.y {
+ let target = regions.expand.select(regions.first, Size::zero());
+ target.x.max(target.y)
+ } else {
+ let size = frames[0].size;
+ let desired = size.x.max(size.y);
+ desired.min(regions.first.x).min(regions.first.y)
+ };
+
+ pod.first = Size::splat(length);
+ pod.expand = Spec::splat(true);
+ frames = child.layout(ctx, &pod, styles)?;
+ }
} else {
// The default size that a shape takes on if it has no child and
// enough space.
let mut size =
Size::new(Length::pt(45.0), Length::pt(30.0)).min(regions.first);
- let length = if regions.expand.x || regions.expand.y {
- let target = regions.expand.select(regions.first, Size::zero());
- target.x.max(target.y)
+ if is_quadratic(S) {
+ let length = if regions.expand.x || regions.expand.y {
+ let target = regions.expand.select(regions.first, Size::zero());
+ target.x.max(target.y)
+ } else {
+ size.x.min(size.y)
+ };
+ size = Size::splat(length);
} else {
- size.x.min(size.y)
- };
- size = Size::splat(length);
+ size = regions.expand.select(regions.first, size);
+ }
frames = vec![Arc::new(Frame::new(size))];
}
@@ -162,27 +167,38 @@ impl<const S: ShapeKind> Layout for AngularNode<S> {
let stroke = match styles.get(Self::STROKE) {
Smart::Auto if fill.is_none() => Sides::splat(Some(Stroke::default())),
Smart::Auto => Sides::splat(None),
- Smart::Custom(strokes) => strokes.map(|s| Some(s.unwrap_or_default())),
+ Smart::Custom(strokes) => strokes.map(|s| s.map(|s| s.unwrap_or_default())),
};
- let radius = {
- let radius = styles.get(Self::RADIUS);
+ let outset = styles.get(Self::OUTSET);
+ let outset = Sides {
+ left: outset.left.relative_to(frame.size.x),
+ top: outset.top.relative_to(frame.size.y),
+ right: outset.right.relative_to(frame.size.x),
+ bottom: outset.bottom.relative_to(frame.size.y),
+ };
- Sides {
- left: radius.left.relative_to(frame.size.x / 2.0),
- top: radius.top.relative_to(frame.size.y / 2.0),
- right: radius.right.relative_to(frame.size.x / 2.0),
- bottom: radius.bottom.relative_to(frame.size.y / 2.0),
- }
+ let size = Spec::new(
+ frame.size.x + outset.left + outset.right,
+ frame.size.y + outset.top + outset.bottom,
+ );
+
+ let radius = styles.get(Self::RADIUS);
+ let radius = Sides {
+ left: radius.left.relative_to(size.x / 2.0),
+ top: radius.top.relative_to(size.y / 2.0),
+ right: radius.right.relative_to(size.x / 2.0),
+ bottom: radius.bottom.relative_to(size.y / 2.0),
};
+
if fill.is_some() || stroke.iter().any(Option::is_some) {
let shape = Shape {
- geometry: Geometry::Rect(frame.size, radius),
+ geometry: Geometry::Rect(size, radius),
fill,
stroke,
};
- frame.prepend(Point::zero(), Element::Shape(shape));
+ frame.prepend(Point::new(-outset.left, -outset.top), Element::Shape(shape));
}
// Apply link if it exists.
@@ -208,3 +224,13 @@ const CIRCLE: ShapeKind = 2;
/// A curve around two focal points.
const ELLIPSE: ShapeKind = 3;
+
+/// Whether a shape kind is curvy.
+fn is_round(kind: ShapeKind) -> bool {
+ matches!(kind, CIRCLE | ELLIPSE)
+}
+
+/// Whether a shape kind has equal side length.
+fn is_quadratic(kind: ShapeKind) -> bool {
+ matches!(kind, SQUARE | CIRCLE)
+}
diff --git a/src/model/styles.rs b/src/model/styles.rs
index 2e752625..00d1df0f 100644
--- a/src/model/styles.rs
+++ b/src/model/styles.rs
@@ -8,7 +8,7 @@ use std::sync::Arc;
use super::{Content, Show, ShowNode};
use crate::diag::{At, TypResult};
use crate::eval::{Args, Func, Node, Smart, Value};
-use crate::geom::{Numeric, Relative, Sides, Spec};
+use crate::geom::{Length, Numeric, Relative, Sides, Spec};
use crate::library::layout::PageNode;
use crate::library::structure::{EnumNode, ListNode};
use crate::library::text::{FontFamily, ParNode, TextNode};
@@ -459,17 +459,30 @@ where
}
}
-impl<T> Fold for Sides<Option<T>>
+impl<T> Fold for Sides<T>
where
- T: Default,
+ T: Fold,
{
- type Output = Sides<T>;
+ type Output = Sides<T::Output>;
+
+ fn fold(self, outer: Self::Output) -> Self::Output {
+ Sides {
+ left: self.left.fold(outer.left),
+ top: self.top.fold(outer.top),
+ right: self.right.fold(outer.right),
+ bottom: self.bottom.fold(outer.bottom),
+ }
+ }
+}
+
+impl Fold for Sides<Option<Relative<Length>>> {
+ type Output = Sides<Relative<Length>>;
fn fold(self, outer: Self::Output) -> Self::Output {
Sides {
left: self.left.unwrap_or(outer.left),
- right: self.right.unwrap_or(outer.right),
top: self.top.unwrap_or(outer.top),
+ right: self.right.unwrap_or(outer.right),
bottom: self.bottom.unwrap_or(outer.bottom),
}
}
diff --git a/tests/typ/code/let.typ b/tests/typ/code/let.typ
index a95d651a..c3be64a5 100644
--- a/tests/typ/code/let.typ
+++ b/tests/typ/code/let.typ
@@ -11,7 +11,7 @@
// Syntax sugar for function definitions.
#let fill = conifer
-#let rect(body) = rect(width: 2cm, fill: fill, padding: 5pt, body)
+#let rect(body) = rect(width: 2cm, fill: fill, inset: 5pt, body)
#rect[Hi!]
---
diff --git a/tests/typ/code/target.typ b/tests/typ/code/target.typ
index 6c321592..b0a3fbf3 100644
--- a/tests/typ/code/target.typ
+++ b/tests/typ/code/target.typ
@@ -7,6 +7,6 @@
#let d = 3
#let value = [hi]
#let item(a, b) = a + b
-#let fn = rect.with(fill: conifer, padding: 5pt)
+#let fn = rect.with(fill: conifer, inset: 5pt)
Some _includable_ text.
diff --git a/tests/typ/graphics/shape-aspect.typ b/tests/typ/graphics/shape-aspect.typ
index 970857b6..70d689f7 100644
--- a/tests/typ/graphics/shape-aspect.typ
+++ b/tests/typ/graphics/shape-aspect.typ
@@ -11,7 +11,7 @@
---
// Test alignment in automatically sized square and circle.
#set text(8pt)
-#square(padding: 4pt)[
+#square(inset: 4pt)[
Hey there, #align(center + bottom, rotate(180deg, [you!]))
]
#circle(align(center + horizon, [Hey.]))
diff --git a/tests/typ/graphics/shape-circle.typ b/tests/typ/graphics/shape-circle.typ
index dc1e3f24..13ff67de 100644
--- a/tests/typ/graphics/shape-circle.typ
+++ b/tests/typ/graphics/shape-circle.typ
@@ -16,13 +16,13 @@ Auto-sized circle. \
Center-aligned rect in auto-sized circle.
#circle(fill: forest, stroke: conifer,
align(center + horizon,
- rect(fill: conifer, padding: 5pt)[But, soft!]
+ rect(fill: conifer, inset: 5pt)[But, soft!]
)
)
Rect in auto-sized circle. \
#circle(fill: forest,
- rect(fill: conifer, stroke: white, padding: 4pt)[
+ rect(fill: conifer, stroke: white, inset: 4pt)[
#set text(8pt)
But, soft! what light through yonder window breaks?
]
diff --git a/tests/typ/graphics/shape-rect.typ b/tests/typ/graphics/shape-rect.typ
index e035fc91..52fe03ea 100644
--- a/tests/typ/graphics/shape-rect.typ
+++ b/tests/typ/graphics/shape-rect.typ
@@ -8,7 +8,7 @@
#set page(width: 150pt)
// Fit to text.
-#rect(fill: conifer, padding: 3pt)[Textbox]
+#rect(fill: conifer, inset: 3pt)[Textbox]
// Empty with fixed width and height.
#block(rect(
@@ -18,7 +18,7 @@
))
// Fixed width, text height.
-#rect(width: 2cm, fill: rgb("9650d6"), padding: 5pt)[Fixed and padded]
+#rect(width: 2cm, fill: rgb("9650d6"), inset: 5pt)[Fixed and padded]
// Page width, fixed height.
#rect(height: 1cm, width: 100%, fill: rgb("734ced"))[Topleft]
diff --git a/tests/typ/graphics/shape-square.typ b/tests/typ/graphics/shape-square.typ
index c4ece778..622fa9c8 100644
--- a/tests/typ/graphics/shape-square.typ
+++ b/tests/typ/graphics/shape-square.typ
@@ -7,7 +7,7 @@
---
// Test auto-sized square.
-#square(fill: eastern, padding: 5pt)[
+#square(fill: eastern, inset: 5pt)[
#set text(fill: white, weight: "bold")
Typst
]
diff --git a/tests/typ/layout/columns.typ b/tests/typ/layout/columns.typ
index ce291fb2..1e77e6bc 100644
--- a/tests/typ/layout/columns.typ
+++ b/tests/typ/layout/columns.typ
@@ -16,7 +16,7 @@
// Test the `columns` function.
#set page(width: auto)
-#rect(width: 180pt, height: 100pt, padding: 8pt, columns(2, [
+#rect(width: 180pt, height: 100pt, inset: 8pt, columns(2, [
A special plight has befallen our document.
Columns in text boxes reigned down unto the soil
to waste a year's crop of rich layouts.
@@ -40,7 +40,7 @@ a page for a test but it does get the job done.
// Test the expansion behavior.
#set page(height: 2.5cm, width: 7.05cm)
-#rect(padding: 6pt, columns(2, [
+#rect(inset: 6pt, columns(2, [
ABC \
BCD
#colbreak()
@@ -73,7 +73,7 @@ D
// Test an empty second column.
#set page(width: 7.05cm, columns: 2)
-#rect(width: 100%, padding: 3pt)[So there isn't anything in the second column?]
+#rect(width: 100%, inset: 3pt)[So there isn't anything in the second column?]
---
// Test columns when one of them is empty.
diff --git a/tests/typ/style/construct.typ b/tests/typ/style/construct.typ
index f01b534b..890c4b94 100644
--- a/tests/typ/style/construct.typ
+++ b/tests/typ/style/construct.typ
@@ -16,17 +16,17 @@
// but the B should be center-aligned.
#set par(align: center)
#par(align: right)[
- A #rect(width: 2cm, fill: conifer, padding: 4pt)[B]
+ A #rect(width: 2cm, fill: conifer, inset: 4pt)[B]
]
---
// The inner rectangle should also be yellow here.
// (and therefore invisible)
-[#set rect(fill: yellow);#text(1em, rect(padding: 5pt, rect()))]
+[#set rect(fill: yellow);#text(1em, rect(inset: 5pt, rect()))]
---
// The inner rectangle should not be yellow here.
-A #rect(fill: yellow, padding: 5pt, rect()) B
+A #rect(fill: yellow, inset: 5pt, rect()) B
---
// The inner list should not be indented extra.