summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/export/pdf.rs18
-rw-r--r--src/layout/background.rs37
-rw-r--r--src/layout/mod.rs23
-rw-r--r--src/layout/rect.rs71
-rw-r--r--src/library/insert.rs37
-rw-r--r--src/library/layout.rs20
-rw-r--r--src/library/mod.rs1
-rw-r--r--tests/library/ref/box.png (renamed from tests/library/ref/geom.png)bin5087 -> 5087 bytes
-rw-r--r--tests/library/typ/box.typ23
-rw-r--r--tests/library/typ/geom.typ23
-rw-r--r--tests/typeset.rs15
11 files changed, 100 insertions, 168 deletions
diff --git a/src/export/pdf.rs b/src/export/pdf.rs
index 7556e370..e5124c21 100644
--- a/src/export/pdf.rs
+++ b/src/export/pdf.rs
@@ -156,19 +156,19 @@ impl<'a> PdfExporter<'a> {
c.b as f32 / 255.,
);
}
- Fill::Image(_) => unimplemented!(),
+ Fill::Image(_) => todo!(),
}
+ let x = pos.x.to_pt() as f32;
+
match &geometry.shape {
Shape::Rect(r) => {
- content.rect(
- pos.x.to_pt() as f32,
- (page.size.height - pos.y - r.size.height).to_pt() as f32,
- r.size.width.to_pt() as f32,
- r.size.height.to_pt() as f32,
- false,
- true,
- );
+ let w = r.width.to_pt() as f32;
+ let h = r.height.to_pt() as f32;
+ let y = (page.size.height - pos.y - r.height).to_pt() as f32;
+ if w > 0.0 && h > 0.0 {
+ content.rect(x, y, w, h, false, true);
+ }
}
}
diff --git a/src/layout/background.rs b/src/layout/background.rs
new file mode 100644
index 00000000..94d5bf45
--- /dev/null
+++ b/src/layout/background.rs
@@ -0,0 +1,37 @@
+use super::*;
+
+/// A node that represents a rectangular box.
+#[derive(Debug, Clone, PartialEq)]
+pub struct NodeBackground {
+ /// The background fill.
+ pub fill: Fill,
+ /// The child node whose sides to pad.
+ pub child: NodeFixed,
+}
+
+impl Layout for NodeBackground {
+ fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted {
+ let mut layouted = self.child.layout(ctx, areas);
+
+ if let Some(first) = layouted.frames_mut().first_mut() {
+ first.elements.insert(
+ 0,
+ (
+ Point::ZERO,
+ Element::Geometry(Geometry {
+ shape: Shape::Rect(first.size),
+ fill: self.fill.clone(),
+ }),
+ ),
+ )
+ }
+
+ layouted
+ }
+}
+
+impl From<NodeBackground> for NodeAny {
+ fn from(background: NodeBackground) -> Self {
+ Self::new(background)
+ }
+}
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 1bb4419d..0c7a6a68 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -4,7 +4,7 @@ mod fixed;
mod node;
mod pad;
mod par;
-mod rect;
+mod background;
mod spacing;
mod stack;
mod text;
@@ -18,7 +18,7 @@ pub use fixed::*;
pub use node::*;
pub use pad::*;
pub use par::*;
-pub use rect::*;
+pub use background::*;
pub use spacing::*;
pub use stack::*;
pub use text::*;
@@ -236,7 +236,6 @@ pub enum Fill {
Color(Color),
/// The fill is an image.
Image(Image),
- // Gradient(Gradient),
}
/// A shape with some kind of fill.
@@ -245,10 +244,10 @@ pub struct Geometry {
/// The shape to draw.
pub shape: Shape,
/// How the shape looks on the inside.
- ///
- /// **TODO:** This could be made into a Vec<Fill> or something such that
- /// the user can compose multiple fills with alpha values less
- /// than one to achieve cool effects.
+ //
+ // TODO: This could be made into a Vec<Fill> or something such that
+ // the user can compose multiple fills with alpha values less
+ // than one to achieve cool effects.
pub fill: Fill,
}
@@ -256,15 +255,7 @@ pub struct Geometry {
#[derive(Debug, Clone, PartialEq)]
pub enum Shape {
/// A rectangle.
- Rect(Rect),
- // Ellipse(Ellipse),
-}
-
-/// An rectangle.
-#[derive(Debug, Clone, PartialEq)]
-pub struct Rect {
- /// The dimensions of the rectangle.
- pub size: Size,
+ Rect(Size),
}
/// An image element.
diff --git a/src/layout/rect.rs b/src/layout/rect.rs
deleted file mode 100644
index ab8e3b07..00000000
--- a/src/layout/rect.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-use std::cmp::Ordering;
-
-use super::*;
-use crate::{color::RgbaColor, geom::Linear};
-
-/// A node that represents a rectangular box.
-#[derive(Debug, Clone, PartialEq)]
-pub struct NodeRect {
- /// The fixed width, if any.
- pub width: Option<Linear>,
- /// The fixed height, if any.
- pub height: Option<Linear>,
- /// The background color.
- pub color: Option<Color>,
- /// The child node whose sides to pad.
- pub child: Node,
-}
-
-impl Layout for NodeRect {
- fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted {
- let Areas { current, full, .. } = areas;
-
- let height_opt = self.height.map(|h| h.resolve(full.height));
- let mut size = Size::new(
- self.width.map(|w| w.resolve(full.width)).unwrap_or(current.width),
- height_opt.unwrap_or(current.height),
- );
-
- let areas = Areas::once(size);
- let mut layouted = self.child.layout(ctx, &areas);
-
- // If the children have some height, apply that,
- // otherwise fall back to zero or the height property.
- if let Some(max) = layouted
- .frames()
- .iter()
- .map(|f| f.size.height)
- .max_by(|x, y| x.partial_cmp(y).unwrap_or(Ordering::Equal))
- {
- size.height = max;
- } else {
- size.height = height_opt.unwrap_or(Length::ZERO)
- }
-
- if let Some(first) = layouted.frames_mut().first_mut() {
- first.elements.insert(
- 0,
- (
- Point::ZERO,
- Element::Geometry(Geometry {
- shape: Shape::Rect(Rect { size }),
- fill: Fill::Color(self.color.unwrap_or(Color::Rgba(RgbaColor {
- r: 255,
- g: 255,
- b: 255,
- a: 0,
- }))),
- }),
- ),
- )
- }
-
- layouted
- }
-}
-
-impl From<NodeRect> for NodeAny {
- fn from(pad: NodeRect) -> Self {
- Self::new(pad)
- }
-}
diff --git a/src/library/insert.rs b/src/library/insert.rs
index 169fad97..58e8a11c 100644
--- a/src/library/insert.rs
+++ b/src/library/insert.rs
@@ -4,43 +4,6 @@ use crate::env::{ImageResource, ResourceId};
use crate::layout::*;
use crate::prelude::*;
-/// `rect`: Layout content into a rectangle that also might have a fill.
-///
-/// # Named arguments
-/// - Width of the box: `width`, of type `linear` relative to parent width.
-/// - Height of the box: `height`, of type `linear` relative to parent height.
-pub fn rect(ctx: &mut EvalContext, args: &mut Args) -> Value {
- let snapshot = ctx.state.clone();
-
- let width = args.get(ctx, "width");
- let height = args.get(ctx, "height");
- let color = args.get(ctx, "color");
-
- let dirs = ctx.state.dirs;
- let align = ctx.state.align;
-
- ctx.start_content_group();
-
- if let Some(body) = args.find::<ValueTemplate>(ctx) {
- body.eval(ctx);
- }
-
- let children = ctx.end_content_group();
-
- let fill_if = |c| if c { Expansion::Fill } else { Expansion::Fit };
- let expand = Spec::new(fill_if(width.is_some()), fill_if(height.is_some()));
-
- ctx.push(NodeRect {
- width,
- height,
- color,
- child: NodeStack { dirs, align, expand, children }.into(),
- });
-
- ctx.state = snapshot;
- Value::None
-}
-
/// `image`: Insert an image.
///
/// Supports PNG and JPEG files.
diff --git a/src/library/layout.rs b/src/library/layout.rs
index 0e04c507..bbcd7898 100644
--- a/src/library/layout.rs
+++ b/src/library/layout.rs
@@ -1,7 +1,7 @@
use std::fmt::{self, Display, Formatter};
-use crate::eval::Softness;
-use crate::layout::{Expansion, NodeFixed, NodeSpacing, NodeStack};
+use crate::{eval::Softness, layout::NodeBackground};
+use crate::layout::{Expansion, Fill, NodeFixed, NodeSpacing, NodeStack};
use crate::paper::{Paper, PaperClass};
use crate::prelude::*;
@@ -175,6 +175,7 @@ impl Display for Alignment {
/// # Named arguments
/// - Width of the box: `width`, of type `linear` relative to parent width.
/// - Height of the box: `height`, of type `linear` relative to parent height.
+/// - Background color of the box: `color`, of type `color`.
pub fn box_(ctx: &mut EvalContext, args: &mut Args) -> Value {
let snapshot = ctx.state.clone();
@@ -182,6 +183,7 @@ pub fn box_(ctx: &mut EvalContext, args: &mut Args) -> Value {
let height = args.get(ctx, "height");
let main = args.get(ctx, "main-dir");
let cross = args.get(ctx, "cross-dir");
+ let color = args.get(ctx, "color");
ctx.set_dirs(Gen::new(main, cross));
@@ -199,11 +201,21 @@ pub fn box_(ctx: &mut EvalContext, args: &mut Args) -> Value {
let fill_if = |c| if c { Expansion::Fill } else { Expansion::Fit };
let expand = Spec::new(fill_if(width.is_some()), fill_if(height.is_some()));
- ctx.push(NodeFixed {
+ let fixed_node = NodeFixed {
width,
height,
child: NodeStack { dirs, align, expand, children }.into(),
- });
+ };
+
+ if let Some(color) = color {
+ ctx.push(NodeBackground {
+ fill: Fill::Color(color),
+ child: fixed_node,
+ })
+ } else {
+ ctx.push(fixed_node);
+ }
+
ctx.state = snapshot;
Value::None
diff --git a/src/library/mod.rs b/src/library/mod.rs
index 7e20f5fb..48da093b 100644
--- a/src/library/mod.rs
+++ b/src/library/mod.rs
@@ -38,7 +38,6 @@ pub fn new() -> Scope {
set!(func: "image", image);
set!(func: "page", page);
set!(func: "pagebreak", pagebreak);
- set!(func: "rect", rect);
set!(func: "rgb", rgb);
set!(func: "type", type_);
set!(func: "v", v);
diff --git a/tests/library/ref/geom.png b/tests/library/ref/box.png
index 37fd7d27..37fd7d27 100644
--- a/tests/library/ref/geom.png
+++ b/tests/library/ref/box.png
Binary files differ
diff --git a/tests/library/typ/box.typ b/tests/library/typ/box.typ
new file mode 100644
index 00000000..03e5da54
--- /dev/null
+++ b/tests/library/typ/box.typ
@@ -0,0 +1,23 @@
+#[page "a5", flip: true]
+
+// Rectangle with width, should have paragraph height
+#[box width: 2cm, color: #9650D6][aa]
+
+Sometimes there is no box
+
+// Rectangle with height, should span line
+#[box height: 2cm, width: 100%, color: #734CED][bb]
+
+// Empty rectangle with width and height
+#[box width: 6cm, height: 12pt, color: #CB4CED]
+
+// This empty rectangle should not be displayed
+#[box width: 2in, color: #ff0000]
+
+// This one should be
+#[box height: 15mm, width: 100%, color: #494DE3]
+
+// These are in a row!
+#[box width: 2in, height: 10pt, color: #D6CD67]
+#[box width: 2in, height: 10pt, color: #EDD466]
+#[box width: 2in, height: 10pt, color: #E3BE62]
diff --git a/tests/library/typ/geom.typ b/tests/library/typ/geom.typ
deleted file mode 100644
index 26ba7ca3..00000000
--- a/tests/library/typ/geom.typ
+++ /dev/null
@@ -1,23 +0,0 @@
-#[page "a5", flip: true]
-
-// Rectangle with width, should have paragraph height
-#[rect width: 2cm, color: #9650D6][aa]
-
-Sometimes there is no box
-
-// Rectangle with height, should span line
-#[rect height: 2cm, color: #734CED][bb]
-
-// Empty rectangle with width and height
-#[rect width: 6cm, height: 12pt, color: #CB4CED]
-
-// This empty rectangle should not be displayed
-#[rect width: 2in, color: #ff0000]
-
-// This one should be
-#[rect height: 15mm, color: #494DE3]
-
-// These are in a row!
-#[rect width: 2in, height: 10pt, color: #D6CD67]
-#[rect width: 2in, height: 10pt, color: #EDD466]
-#[rect width: 2in, height: 10pt, color: #E3BE62]
diff --git a/tests/typeset.rs b/tests/typeset.rs
index 432941ce..b1f4ede2 100644
--- a/tests/typeset.rs
+++ b/tests/typeset.rs
@@ -451,10 +451,6 @@ fn draw_geometry(canvas: &mut Canvas, pos: Point, _: &Env, element: &Geometry) {
let x = pos.x.to_pt() as f32;
let y = pos.y.to_pt() as f32;
- let (w, h) = match &element.shape {
- Shape::Rect(s) => (s.size.width.to_pt() as f32, s.size.height.to_pt() as f32),
- };
-
let mut paint = Paint::default();
match &element.fill {
@@ -464,9 +460,14 @@ fn draw_geometry(canvas: &mut Canvas, pos: Point, _: &Env, element: &Geometry) {
Fill::Image(_) => todo!(),
};
- if let Some(rect) = Rect::from_xywh(x, y, w, h) {
- canvas.fill_rect(rect, &paint);
- }
+ match &element.shape {
+ Shape::Rect(s) => {
+ let (w, h) = (s.width.to_pt() as f32, s.height.to_pt() as f32);
+ canvas.fill_rect(Rect::from_xywh(x, y, w, h).unwrap(), &paint);
+ },
+ };
+
+
}
fn draw_image(canvas: &mut Canvas, pos: Point, env: &Env, element: &Image) {