diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs index 4307d2f92..801a137d9 100644 --- a/src/library/layout/page.rs +++ b/src/library/layout/page.rs @@ -18,14 +18,9 @@ impl PageNode { /// Whether the page is flipped into landscape orientation. pub const FLIPPED: bool = false; - /// The left margin. - pub const LEFT: Smart> = Smart::Auto; - /// The right margin. - pub const RIGHT: Smart> = Smart::Auto; - /// The top margin. - pub const TOP: Smart> = Smart::Auto; - /// The bottom margin. - pub const BOTTOM: Smart> = Smart::Auto; + /// The page margin. + #[property(fold)] + pub const MARGINS: Sides>> = Sides::splat(Smart::Auto); /// How many columns the page has. pub const COLUMNS: NonZeroUsize = NonZeroUsize::new(1).unwrap(); @@ -54,13 +49,7 @@ impl PageNode { styles.set_opt(Self::WIDTH, args.named("width")?); styles.set_opt(Self::HEIGHT, args.named("height")?); - let all = args.named("margins")?; - let hor = args.named("horizontal")?; - let ver = args.named("vertical")?; - styles.set_opt(Self::LEFT, args.named("left")?.or(hor).or(all)); - styles.set_opt(Self::TOP, args.named("top")?.or(ver).or(all)); - styles.set_opt(Self::RIGHT, args.named("right")?.or(hor).or(all)); - styles.set_opt(Self::BOTTOM, args.named("bottom")?.or(ver).or(all)); + styles.set_opt(Self::MARGINS, args.named("margins")?); styles.set_opt(Self::FLIPPED, args.named("flipped")?); styles.set_opt(Self::FILL, args.named("fill")?); @@ -96,12 +85,7 @@ impl PageNode { // Determine the margins. let default = Relative::from(0.1190 * min); - let padding = Sides { - left: styles.get(Self::LEFT).unwrap_or(default), - right: styles.get(Self::RIGHT).unwrap_or(default), - top: styles.get(Self::TOP).unwrap_or(default), - bottom: styles.get(Self::BOTTOM).unwrap_or(default), - }; + let padding = styles.get(Self::MARGINS).map(|side| side.unwrap_or(default)); let mut child = self.0.clone(); diff --git a/src/model/styles.rs b/src/model/styles.rs index 00d1df0fa..1fddfd0ed 100644 --- a/src/model/styles.rs +++ b/src/model/styles.rs @@ -7,7 +7,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::eval::{Args, Func, Node, RawLength, Smart, Value}; use crate::geom::{Length, Numeric, Relative, Sides, Spec}; use crate::library::layout::PageNode; use crate::library::structure::{EnumNode, ListNode}; @@ -488,6 +488,19 @@ impl Fold for Sides>> { } } +impl Fold for Sides>> { + type Output = Sides>>; + + fn fold(self, outer: Self::Output) -> Self::Output { + Sides { + left: self.left.or(outer.left), + top: self.top.or(outer.top), + right: self.right.or(outer.right), + bottom: self.bottom.or(outer.bottom), + } + } +} + /// A scoped property barrier. /// /// Barriers interact with [scoped](StyleMap::scoped) styles: A scoped style diff --git a/tests/ref/layout/page.png b/tests/ref/layout/page.png index 35716e4de..e0618e589 100644 Binary files a/tests/ref/layout/page.png and b/tests/ref/layout/page.png differ diff --git a/tests/typ/layout/page-margin.typ b/tests/typ/layout/page-margin.typ index 44126d2da..e30518b02 100644 --- a/tests/typ/layout/page-margin.typ +++ b/tests/typ/layout/page-margin.typ @@ -11,10 +11,10 @@ --- // Set individual margins. #set page(height: 40pt) -[#set page(left: 0pt); #align(left)[Left]] -[#set page(right: 0pt); #align(right)[Right]] -[#set page(top: 0pt); #align(top)[Top]] -[#set page(bottom: 0pt); #align(bottom)[Bottom]] +[#set page(margins: (left: 0pt,)); #align(left)[Left]] +[#set page(margins: (right: 0pt,)); #align(right)[Right]] +[#set page(margins: (top: 0pt,)); #align(top)[Top]] +[#set page(margins: (bottom: 0pt,)); #align(bottom)[Bottom]] // Ensure that specific margins override general margins. -[#set page(margins: 0pt, left: 20pt); Overriden] +[#set page(margins: (rest: 0pt, left: 20pt)); Overriden] diff --git a/tests/typ/layout/page-marginals.typ b/tests/typ/layout/page-marginals.typ index 9fd193c62..6e8e3d853 100644 --- a/tests/typ/layout/page-marginals.typ +++ b/tests/typ/layout/page-marginals.typ @@ -1,7 +1,6 @@ #set page( paper: "a8", - margins: 30pt, - horizontal: 15pt, + margins: (x: 15pt, y: 30pt), header: align(horizon, { text(eastern)[*Typst*] h(1fr) @@ -18,5 +17,5 @@ do wear it; cast it off. It is my lady, O, it is my love! O, that she knew she were! She speaks yet she says nothing: what of that? Her eye discourses; I will answer it. -#set page(header: none, height: auto, top: 15pt, bottom: 25pt) +#set page(header: none, height: auto, margins: (top: 15pt, bottom: 25pt)) The END. diff --git a/tests/typ/layout/page.typ b/tests/typ/layout/page.typ index 89d0f2fbd..3157ebf93 100644 --- a/tests/typ/layout/page.typ +++ b/tests/typ/layout/page.typ @@ -24,7 +24,7 @@ // Test page fill. #set page(width: 80pt, height: 40pt, fill: eastern) #text(15pt, "Roboto", fill: white, smallcaps: true)[Typst] -#page(width: 40pt, fill: none, margins: auto, top: 10pt)[Hi] +#page(width: 40pt, fill: none, margins: (top: 10pt, rest: auto))[Hi] --- // Just page followed by pagebreak. diff --git a/tests/typeset.rs b/tests/typeset.rs index 9f84a733a..d3f7844b1 100644 --- a/tests/typeset.rs +++ b/tests/typeset.rs @@ -12,7 +12,7 @@ use walkdir::WalkDir; use typst::diag::Error; use typst::eval::{Smart, Value}; use typst::frame::{Element, Frame}; -use typst::geom::{Length, RgbaColor}; +use typst::geom::{Length, RgbaColor, Sides}; use typst::library::layout::PageNode; use typst::library::text::{TextNode, TextSize}; use typst::loading::FsLoader; @@ -64,10 +64,10 @@ fn main() { let mut styles = StyleMap::new(); styles.set(PageNode::WIDTH, Smart::Custom(Length::pt(120.0).into())); styles.set(PageNode::HEIGHT, Smart::Auto); - styles.set(PageNode::LEFT, Smart::Custom(Length::pt(10.0).into())); - styles.set(PageNode::TOP, Smart::Custom(Length::pt(10.0).into())); - styles.set(PageNode::RIGHT, Smart::Custom(Length::pt(10.0).into())); - styles.set(PageNode::BOTTOM, Smart::Custom(Length::pt(10.0).into())); + styles.set( + PageNode::MARGINS, + Sides::splat(Smart::Custom(Length::pt(10.0).into())), + ); styles.set(TextNode::SIZE, TextSize(Length::pt(10.0).into())); // Hook up an assert function into the global scope.