New ShapeNode
Replaces `BackgroundNode` and `FixedNode`
@ -1,55 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
/// A node that places a rectangular filled background behind its child.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub struct BackgroundNode {
|
||||
/// The kind of shape to use as a background.
|
||||
pub shape: BackgroundShape,
|
||||
/// Background color / texture.
|
||||
pub fill: Paint,
|
||||
/// The child node to be filled.
|
||||
pub child: LayoutNode,
|
||||
}
|
||||
|
||||
/// The kind of shape to use as a background.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum BackgroundShape {
|
||||
Rect,
|
||||
Ellipse,
|
||||
}
|
||||
|
||||
impl Layout for BackgroundNode {
|
||||
fn layout(
|
||||
&self,
|
||||
ctx: &mut LayoutContext,
|
||||
regions: &Regions,
|
||||
) -> Vec<Constrained<Rc<Frame>>> {
|
||||
let mut frames = self.child.layout(ctx, regions);
|
||||
|
||||
for Constrained { item: frame, .. } in &mut frames {
|
||||
let (point, geometry) = match self.shape {
|
||||
BackgroundShape::Rect => (Point::zero(), Geometry::Rect(frame.size)),
|
||||
BackgroundShape::Ellipse => {
|
||||
(frame.size.to_point() / 2.0, Geometry::Ellipse(frame.size))
|
||||
}
|
||||
};
|
||||
|
||||
// Create a new frame with the background geometry and the child's
|
||||
// frame.
|
||||
let empty = Frame::new(frame.size, frame.baseline);
|
||||
let prev = std::mem::replace(frame, Rc::new(empty));
|
||||
let new = Rc::make_mut(frame);
|
||||
new.push(point, Element::Geometry(geometry, self.fill));
|
||||
new.push_frame(Point::zero(), prev);
|
||||
}
|
||||
|
||||
frames
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BackgroundNode> for LayoutNode {
|
||||
fn from(background: BackgroundNode) -> Self {
|
||||
Self::new(background)
|
||||
}
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
use decorum::N64;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// A node that can fix its child's width and height.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub struct FixedNode {
|
||||
/// The fixed width, if any.
|
||||
pub width: Option<Linear>,
|
||||
/// The fixed height, if any.
|
||||
pub height: Option<Linear>,
|
||||
/// The fixed aspect ratio between width and height.
|
||||
///
|
||||
/// The resulting frame will satisfy `width = aspect * height`.
|
||||
pub aspect: Option<N64>,
|
||||
/// The child node whose size to fix.
|
||||
pub child: LayoutNode,
|
||||
}
|
||||
|
||||
impl Layout for FixedNode {
|
||||
fn layout(
|
||||
&self,
|
||||
ctx: &mut LayoutContext,
|
||||
regions: &Regions,
|
||||
) -> Vec<Constrained<Rc<Frame>>> {
|
||||
// Fill in width or height if aspect ratio and the other is given.
|
||||
let aspect = self.aspect.map(N64::into_inner);
|
||||
let width = self.width.or(self.height.zip(aspect).map(|(h, a)| a * h));
|
||||
let height = self.height.or(self.width.zip(aspect).map(|(w, a)| w / a));
|
||||
|
||||
// Resolve the linears based on the current width and height.
|
||||
let mut child_size = Size::new(
|
||||
width.map_or(regions.current.w, |w| w.resolve(regions.base.w)),
|
||||
height.map_or(regions.current.h, |h| h.resolve(regions.base.h)),
|
||||
);
|
||||
|
||||
// If width or height aren't set for an axis, the base should be
|
||||
// inherited from the parent for that axis.
|
||||
let child_base = Size::new(
|
||||
if width.is_some() { child_size.w } else { regions.base.w },
|
||||
if height.is_some() { child_size.h } else { regions.base.h },
|
||||
);
|
||||
|
||||
// Prepare constraints.
|
||||
let mut constraints = Constraints::new(regions.expand);
|
||||
constraints.set_base_if_linear(regions.base, Spec::new(width, height));
|
||||
|
||||
// If the size for one axis isn't specified, the `current` size along
|
||||
// that axis needs to remain the same for the result to be reusable.
|
||||
if width.is_none() {
|
||||
constraints.exact.x = Some(regions.current.w);
|
||||
}
|
||||
if height.is_none() {
|
||||
constraints.exact.y = Some(regions.current.h);
|
||||
}
|
||||
|
||||
// Apply the aspect ratio.
|
||||
if let Some(aspect) = aspect {
|
||||
let width = child_size.w.min(aspect * child_size.h);
|
||||
child_size = Size::new(width, width / aspect);
|
||||
constraints.exact = regions.current.to_spec().map(Some);
|
||||
constraints.min = Spec::splat(None);
|
||||
constraints.max = Spec::splat(None);
|
||||
}
|
||||
|
||||
// If width or height are fixed, the child should fill the available
|
||||
// space along that axis.
|
||||
let child_expand = Spec::new(width.is_some(), height.is_some());
|
||||
|
||||
// Layout the child.
|
||||
let mut regions = Regions::one(child_size, child_base, child_expand);
|
||||
let mut frames = self.child.layout(ctx, ®ions);
|
||||
|
||||
// If we have an aspect ratio and the child is content-sized, we need to
|
||||
// relayout with expansion.
|
||||
if let Some(aspect) = aspect {
|
||||
if width.is_none() && height.is_none() {
|
||||
let needed = frames[0].item.size.cap(child_size);
|
||||
let width = needed.w.max(aspect * needed.h);
|
||||
regions.current = Size::new(width, width / aspect);
|
||||
regions.expand = Spec::splat(true);
|
||||
frames = self.child.layout(ctx, ®ions);
|
||||
}
|
||||
}
|
||||
|
||||
// Overwrite the child's constraints with ours.
|
||||
assert_eq!(frames.len(), 1);
|
||||
frames[0].constraints = constraints;
|
||||
|
||||
frames
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FixedNode> for LayoutNode {
|
||||
fn from(fixed: FixedNode) -> Self {
|
||||
Self::new(fixed)
|
||||
}
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
//! Layouting.
|
||||
|
||||
mod background;
|
||||
mod constraints;
|
||||
mod fixed;
|
||||
mod frame;
|
||||
mod grid;
|
||||
mod image;
|
||||
@ -11,14 +9,13 @@ mod incremental;
|
||||
mod pad;
|
||||
mod par;
|
||||
mod regions;
|
||||
mod shape;
|
||||
mod shaping;
|
||||
mod stack;
|
||||
mod tree;
|
||||
|
||||
pub use self::image::*;
|
||||
pub use background::*;
|
||||
pub use constraints::*;
|
||||
pub use fixed::*;
|
||||
pub use frame::*;
|
||||
pub use grid::*;
|
||||
#[cfg(feature = "layout-cache")]
|
||||
@ -26,6 +23,7 @@ pub use incremental::*;
|
||||
pub use pad::*;
|
||||
pub use par::*;
|
||||
pub use regions::*;
|
||||
pub use shape::*;
|
||||
pub use shaping::*;
|
||||
pub use stack::*;
|
||||
pub use tree::*;
|
||||
|
141
src/layout/shape.rs
Normal file
@ -0,0 +1,141 @@
|
||||
use std::f64::consts::SQRT_2;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Places its child into a sizable and fillable shape.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub struct ShapeNode {
|
||||
/// Which shape to place the child into.
|
||||
pub shape: ShapeKind,
|
||||
/// The width, if any.
|
||||
pub width: Option<Linear>,
|
||||
/// The height, if any.
|
||||
pub height: Option<Linear>,
|
||||
/// How to fill the shape, if at all.
|
||||
pub fill: Option<Paint>,
|
||||
/// The child node to place into the shape, if any.
|
||||
pub child: Option<LayoutNode>,
|
||||
}
|
||||
|
||||
/// The type of a shape.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum ShapeKind {
|
||||
/// A rectangle with equal side lengths.
|
||||
Square,
|
||||
/// A quadrilateral with four right angles.
|
||||
Rect,
|
||||
/// An ellipse with coinciding foci.
|
||||
Circle,
|
||||
/// A curve around two focal points.
|
||||
Ellipse,
|
||||
}
|
||||
|
||||
impl Layout for ShapeNode {
|
||||
fn layout(
|
||||
&self,
|
||||
ctx: &mut LayoutContext,
|
||||
regions: &Regions,
|
||||
) -> Vec<Constrained<Rc<Frame>>> {
|
||||
// Resolve width and height relative to the region's base.
|
||||
let width = self.width.map(|w| w.resolve(regions.base.w));
|
||||
let height = self.height.map(|h| h.resolve(regions.base.h));
|
||||
|
||||
// Generate constraints.
|
||||
let constraints = {
|
||||
let mut cts = Constraints::new(regions.expand);
|
||||
cts.set_base_if_linear(regions.base, Spec::new(self.width, self.height));
|
||||
|
||||
// Set exact and base constraint if child is automatically sized.
|
||||
if self.width.is_none() {
|
||||
cts.exact.x = Some(regions.current.w);
|
||||
cts.base.x = Some(regions.base.w);
|
||||
}
|
||||
|
||||
// Same here.
|
||||
if self.height.is_none() {
|
||||
cts.exact.y = Some(regions.current.h);
|
||||
cts.base.y = Some(regions.base.h);
|
||||
}
|
||||
|
||||
cts
|
||||
};
|
||||
|
||||
// Layout.
|
||||
let mut frames = if let Some(child) = &self.child {
|
||||
let mut node: &dyn Layout = child;
|
||||
|
||||
let padded;
|
||||
if matches!(self.shape, ShapeKind::Circle | ShapeKind::Ellipse) {
|
||||
// Padding with this ratio ensures that a rectangular child fits
|
||||
// perfectly into a circle / an ellipse.
|
||||
padded = PadNode {
|
||||
padding: Sides::splat(Relative::new(0.5 - SQRT_2 / 4.0).into()),
|
||||
child: child.clone(),
|
||||
};
|
||||
node = &padded;
|
||||
}
|
||||
|
||||
// The "pod" is the region into which the child will be layouted.
|
||||
let mut pod = {
|
||||
let size = Size::new(
|
||||
width.unwrap_or(regions.current.w),
|
||||
height.unwrap_or(regions.current.h),
|
||||
);
|
||||
|
||||
let base = Size::new(
|
||||
if width.is_some() { size.w } else { regions.base.w },
|
||||
if height.is_some() { size.h } else { regions.base.h },
|
||||
);
|
||||
|
||||
let expand = Spec::new(width.is_some(), height.is_some());
|
||||
Regions::one(size, base, expand)
|
||||
};
|
||||
|
||||
// Now, layout the child.
|
||||
let mut frames = node.layout(ctx, &pod);
|
||||
|
||||
if matches!(self.shape, ShapeKind::Square | ShapeKind::Circle) {
|
||||
// Relayout with full expansion into square region to make sure
|
||||
// the result is really a square or circle.
|
||||
let size = frames[0].item.size;
|
||||
pod.current.w = size.w.max(size.h).min(pod.current.w);
|
||||
pod.current.h = pod.current.w;
|
||||
pod.expand = Spec::splat(true);
|
||||
frames = node.layout(ctx, &pod);
|
||||
}
|
||||
|
||||
// Validate and set constraints.
|
||||
assert_eq!(frames.len(), 1);
|
||||
frames[0].constraints = constraints;
|
||||
frames
|
||||
} else {
|
||||
// Resolve shape size.
|
||||
let size = Size::new(width.unwrap_or_default(), height.unwrap_or_default());
|
||||
vec![Frame::new(size, size.h).constrain(constraints)]
|
||||
};
|
||||
|
||||
// Add background shape if desired.
|
||||
if let Some(fill) = self.fill {
|
||||
let frame = Rc::make_mut(&mut frames[0].item);
|
||||
let (pos, geometry) = match self.shape {
|
||||
ShapeKind::Square | ShapeKind::Rect => {
|
||||
(Point::zero(), Geometry::Rect(frame.size))
|
||||
}
|
||||
ShapeKind::Circle | ShapeKind::Ellipse => {
|
||||
(frame.size.to_point() / 2.0, Geometry::Ellipse(frame.size))
|
||||
}
|
||||
};
|
||||
|
||||
frame.prepend(pos, Element::Geometry(geometry, fill));
|
||||
}
|
||||
|
||||
frames
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ShapeNode> for LayoutNode {
|
||||
fn from(shape: ShapeNode) -> Self {
|
||||
Self::new(shape)
|
||||
}
|
||||
}
|
@ -50,8 +50,9 @@ impl PageRun {
|
||||
}
|
||||
|
||||
/// A dynamic layouting node.
|
||||
#[derive(Clone)]
|
||||
pub struct LayoutNode {
|
||||
node: Box<dyn Layout>,
|
||||
node: Rc<dyn Layout>,
|
||||
#[cfg(feature = "layout-cache")]
|
||||
hash: u64,
|
||||
}
|
||||
@ -63,7 +64,7 @@ impl LayoutNode {
|
||||
where
|
||||
T: Layout + 'static,
|
||||
{
|
||||
Self { node: Box::new(node) }
|
||||
Self { node: Rc::new(node) }
|
||||
}
|
||||
|
||||
/// Create a new instance from any node that satisifies the required bounds.
|
||||
@ -79,7 +80,7 @@ impl LayoutNode {
|
||||
state.finish()
|
||||
};
|
||||
|
||||
Self { node: Box::new(node), hash }
|
||||
Self { node: Rc::new(node), hash }
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,10 +100,16 @@ impl Layout for LayoutNode {
|
||||
ctx.level -= 1;
|
||||
|
||||
let entry = FramesEntry::new(frames.clone(), ctx.level);
|
||||
debug_assert!(
|
||||
entry.check(regions),
|
||||
"constraints did not match regions they were created for",
|
||||
);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
if !entry.check(regions) {
|
||||
eprintln!("regions: {:#?}", regions);
|
||||
eprintln!(
|
||||
"constraints: {:#?}",
|
||||
frames.iter().map(|c| c.constraints).collect::<Vec<_>>()
|
||||
);
|
||||
panic!("constraints did not match regions they were created for");
|
||||
}
|
||||
|
||||
ctx.layouts.insert(self.hash, entry);
|
||||
frames
|
||||
|
@ -1,11 +1,8 @@
|
||||
use std::f64::consts::SQRT_2;
|
||||
use std::io;
|
||||
|
||||
use decorum::N64;
|
||||
|
||||
use super::*;
|
||||
use crate::diag::Error;
|
||||
use crate::layout::{BackgroundNode, BackgroundShape, FixedNode, ImageNode, PadNode};
|
||||
use crate::layout::{ImageNode, ShapeKind, ShapeNode};
|
||||
|
||||
/// `image`: An image.
|
||||
pub fn image(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||
@ -33,52 +30,24 @@ 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.eat().unwrap_or_default();
|
||||
Ok(rect_impl(width, height, None, fill, body))
|
||||
let body = args.eat();
|
||||
Ok(shape_impl(ShapeKind::Rect, width, height, fill, body))
|
||||
}
|
||||
|
||||
/// `square`: A square with optional content.
|
||||
pub fn square(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||
let size = args.named::<Length>("size")?.map(Linear::from);
|
||||
let width = match size {
|
||||
Some(size) => Some(size),
|
||||
None => args.named("width")?,
|
||||
size => size,
|
||||
};
|
||||
let height = match width {
|
||||
Some(_) => None,
|
||||
let height = match size {
|
||||
None => args.named("height")?,
|
||||
size => size,
|
||||
};
|
||||
let aspect = Some(N64::from(1.0));
|
||||
let fill = args.named("fill")?;
|
||||
let body = args.eat().unwrap_or_default();
|
||||
Ok(rect_impl(width, height, aspect, fill, body))
|
||||
}
|
||||
|
||||
fn rect_impl(
|
||||
width: Option<Linear>,
|
||||
height: Option<Linear>,
|
||||
aspect: Option<N64>,
|
||||
fill: Option<Color>,
|
||||
body: Template,
|
||||
) -> Value {
|
||||
Value::Template(Template::from_inline(move |style| {
|
||||
let mut node = LayoutNode::new(FixedNode {
|
||||
width,
|
||||
height,
|
||||
aspect,
|
||||
child: body.to_stack(style).into(),
|
||||
});
|
||||
|
||||
if let Some(fill) = fill {
|
||||
node = LayoutNode::new(BackgroundNode {
|
||||
shape: BackgroundShape::Rect,
|
||||
fill: Paint::Color(fill),
|
||||
child: node,
|
||||
});
|
||||
}
|
||||
|
||||
node
|
||||
}))
|
||||
let body = args.eat();
|
||||
Ok(shape_impl(ShapeKind::Square, width, height, fill, body))
|
||||
}
|
||||
|
||||
/// `ellipse`: An ellipse with optional content.
|
||||
@ -86,8 +55,8 @@ 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.eat().unwrap_or_default();
|
||||
Ok(ellipse_impl(width, height, None, fill, body))
|
||||
let body = args.eat();
|
||||
Ok(shape_impl(ShapeKind::Ellipse, width, height, fill, body))
|
||||
}
|
||||
|
||||
/// `circle`: A circle with optional content.
|
||||
@ -97,46 +66,39 @@ pub fn circle(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||
None => args.named("width")?,
|
||||
diameter => diameter,
|
||||
};
|
||||
let height = match width {
|
||||
let height = match diameter {
|
||||
None => args.named("height")?,
|
||||
width => width,
|
||||
diameter => diameter,
|
||||
};
|
||||
let aspect = Some(N64::from(1.0));
|
||||
let fill = args.named("fill")?;
|
||||
let body = args.eat().unwrap_or_default();
|
||||
Ok(ellipse_impl(width, height, aspect, fill, body))
|
||||
let body = args.eat();
|
||||
Ok(shape_impl(ShapeKind::Circle, width, height, fill, body))
|
||||
}
|
||||
|
||||
fn ellipse_impl(
|
||||
width: Option<Linear>,
|
||||
height: Option<Linear>,
|
||||
aspect: Option<N64>,
|
||||
fn shape_impl(
|
||||
shape: ShapeKind,
|
||||
mut width: Option<Linear>,
|
||||
mut height: Option<Linear>,
|
||||
fill: Option<Color>,
|
||||
body: Template,
|
||||
body: Option<Template>,
|
||||
) -> Value {
|
||||
Value::Template(Template::from_inline(move |style| {
|
||||
// This padding ratio ensures that the rectangular padded region fits
|
||||
// perfectly into the ellipse.
|
||||
const PAD: f64 = 0.5 - SQRT_2 / 4.0;
|
||||
|
||||
let mut node = LayoutNode::new(FixedNode {
|
||||
width,
|
||||
height,
|
||||
aspect,
|
||||
child: LayoutNode::new(PadNode {
|
||||
padding: Sides::splat(Relative::new(PAD).into()),
|
||||
child: body.to_stack(style).into(),
|
||||
}),
|
||||
// Set default shape size if there's no body.
|
||||
if body.is_none() {
|
||||
let v = Length::pt(30.0).into();
|
||||
height.get_or_insert(v);
|
||||
width.get_or_insert(match shape {
|
||||
ShapeKind::Square | ShapeKind::Circle => v,
|
||||
ShapeKind::Rect | ShapeKind::Ellipse => 1.5 * v,
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(fill) = fill {
|
||||
node = LayoutNode::new(BackgroundNode {
|
||||
shape: BackgroundShape::Ellipse,
|
||||
fill: Paint::Color(fill),
|
||||
child: node,
|
||||
});
|
||||
}
|
||||
|
||||
node
|
||||
Value::Template(Template::from_inline(move |style| ShapeNode {
|
||||
shape,
|
||||
width,
|
||||
height,
|
||||
fill: Some(Paint::Color(
|
||||
fill.unwrap_or(Color::Rgba(RgbaColor::new(175, 175, 175, 255))),
|
||||
)),
|
||||
child: body.as_ref().map(|template| template.to_stack(style).into()),
|
||||
}))
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
use super::*;
|
||||
use crate::layout::{FixedNode, GridNode, PadNode, StackChild, StackNode, TrackSizing};
|
||||
use crate::layout::{
|
||||
GridNode, PadNode, ShapeKind, ShapeNode, StackChild, StackNode, TrackSizing,
|
||||
};
|
||||
use crate::style::{Paper, PaperClass};
|
||||
|
||||
/// `page`: Configure pages.
|
||||
@ -146,13 +148,15 @@ pub fn v(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||
pub fn boxed(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||
let width = args.named("width")?;
|
||||
let height = args.named("height")?;
|
||||
let fill = args.named("fill")?;
|
||||
let body: Template = args.eat().unwrap_or_default();
|
||||
Ok(Value::Template(Template::from_inline(move |style| {
|
||||
FixedNode {
|
||||
ShapeNode {
|
||||
shape: ShapeKind::Rect,
|
||||
width,
|
||||
height,
|
||||
aspect: None,
|
||||
child: body.to_stack(style).into(),
|
||||
fill: fill.map(Paint::Color),
|
||||
child: Some(body.to_stack(style).into()),
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ use crate::diag::{At, TypResult};
|
||||
use crate::eval::{Args, Array, EvalContext, Scope, Str, Template, Value};
|
||||
use crate::font::{FontFamily, FontStretch, FontStyle, FontWeight, VerticalFontMetric};
|
||||
use crate::geom::*;
|
||||
use crate::layout::LayoutNode;
|
||||
use crate::style::Style;
|
||||
use crate::syntax::{Span, Spanned};
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.8 KiB |
@ -10,18 +10,12 @@
|
||||
#let university = [*Technische Universität {city}*]
|
||||
#let faculty = [*Fakultät II, Institut for Mathematik*]
|
||||
|
||||
// The `box` function just places content into a rectangular container. When
|
||||
// the only argument to a function is a template, the parentheses can be omitted
|
||||
// (i.e. `f[a]` is the same as `f([a])`).
|
||||
#box[
|
||||
// Backslash adds a forced line break.
|
||||
#university \
|
||||
#faculty \
|
||||
Sekretariat MA \
|
||||
Dr. Max Mustermann \
|
||||
Ola Nordmann, John Doe
|
||||
]
|
||||
#align(right, box[*WiSe 2019/2020* \ Woche 3])
|
||||
// Backslashs add forced line breaks.
|
||||
#university #align(right)[*WiSe 2019/2020*] \
|
||||
#faculty #align(right)[Woche 3] \
|
||||
Sekretariat MA \
|
||||
Dr. Max Mustermann \
|
||||
Ola Nordmann, John Doe
|
||||
|
||||
// Adds vertical spacing.
|
||||
#v(6mm)
|
||||
|
@ -1,5 +1,9 @@
|
||||
// Test the `circle` function.
|
||||
|
||||
---
|
||||
// Default circle.
|
||||
#circle()
|
||||
|
||||
---
|
||||
// Test auto sizing.
|
||||
|
||||
@ -29,20 +33,15 @@ Expanded by height.
|
||||
|
||||
---
|
||||
// Test relative sizing.
|
||||
#rect(width: 100%, height: 50pt, fill: rgb("aaa"))[
|
||||
#rect(width: 100pt, height: 50pt, fill: rgb("aaa"))[
|
||||
#align(center, center)
|
||||
#font(fill: white)
|
||||
#circle(radius: 10pt, fill: eastern)[A]
|
||||
#circle(height: 60%, fill: eastern)[B]
|
||||
#circle(width: 20% + 20pt, fill: eastern)[C]
|
||||
#circle(radius: 10pt, fill: eastern)[A] // D=20pt
|
||||
#circle(height: 60%, fill: eastern)[B] // D=30pt
|
||||
#circle(width: 20% + 20pt, fill: eastern)[C] // D=40pt
|
||||
]
|
||||
|
||||
---
|
||||
// Radius wins over width and height.
|
||||
// Error: 23-34 unexpected argument
|
||||
#circle(radius: 10pt, width: 50pt, height: 100pt, fill: eastern)
|
||||
|
||||
---
|
||||
// Width wins over height.
|
||||
// Error: 9-21 unexpected argument
|
||||
#circle(height: 50pt, width: 20pt, fill: eastern)
|
||||
|
@ -1,5 +1,9 @@
|
||||
// Test the `ellipse` function.
|
||||
|
||||
---
|
||||
// Default ellipse.
|
||||
#ellipse()
|
||||
|
||||
---
|
||||
100% rect in 100% ellipse in fixed rect. \
|
||||
#rect(width: 3cm, height: 2cm, fill: rgb("2a631a"),
|
||||
|
@ -1,27 +1,25 @@
|
||||
// Test shapes.
|
||||
|
||||
---
|
||||
// Test the `rect` function.
|
||||
|
||||
---
|
||||
// Default rectangle.
|
||||
#rect()
|
||||
|
||||
---
|
||||
#page(width: 150pt)
|
||||
|
||||
// Fit to text.
|
||||
#rect(fill: conifer)[Textbox]
|
||||
|
||||
// Empty with fixed width and height.
|
||||
#rect(width: 3cm, height: 12pt, fill: rgb("CB4CED"))
|
||||
#rect(width: 3cm, height: 12pt, fill: rgb("ed8a4c"))
|
||||
|
||||
// Fixed width, text height.
|
||||
#rect(width: 2cm, fill: rgb("9650D6"), pad(5pt)[Fixed and padded])
|
||||
#rect(width: 2cm, fill: rgb("9650d6"), pad(5pt)[Fixed and padded])
|
||||
|
||||
// Page width, fixed height.
|
||||
#rect(height: 1cm, width: 100%, fill: rgb("734CED"))[Topleft]
|
||||
#rect(height: 1cm, width: 100%, fill: rgb("734ced"))[Topleft]
|
||||
|
||||
// Not visible, but creates a gap between the boxes above and below
|
||||
// due to line spacing.
|
||||
#rect(width: 1in, fill: rgb("ff0000"))
|
||||
|
||||
// These are in a row!
|
||||
#rect(width: 0.5in, height: 10pt, fill: rgb("D6CD67"))
|
||||
#rect(width: 0.5in, height: 10pt, fill: rgb("EDD466"))
|
||||
#rect(width: 0.5in, height: 10pt, fill: rgb("E3BE62"))
|
||||
// These are inline with text.
|
||||
\{#rect(width: 0.5in, height: 7pt, fill: rgb("d6cd67"))
|
||||
#rect(width: 0.5in, height: 7pt, fill: rgb("edd466"))
|
||||
#rect(width: 0.5in, height: 7pt, fill: rgb("e3be62"))\}
|
||||
|
@ -1,5 +1,10 @@
|
||||
// Test the `square` function.
|
||||
|
||||
---
|
||||
// Default square.
|
||||
#square()
|
||||
#square[hey!]
|
||||
|
||||
---
|
||||
// Test auto-sized square.
|
||||
#square(fill: eastern)[
|
||||
@ -7,6 +12,7 @@
|
||||
#align(center)
|
||||
#pad(5pt)[Typst]
|
||||
]
|
||||
|
||||
---
|
||||
// Test relative-sized child.
|
||||
#square(fill: eastern)[
|
||||
@ -15,14 +21,14 @@
|
||||
]
|
||||
|
||||
---
|
||||
// Test height overflow.
|
||||
// Test text overflowing height.
|
||||
#page(width: 75pt, height: 100pt)
|
||||
#square(fill: conifer)[
|
||||
But, soft! what light through yonder window breaks?
|
||||
]
|
||||
|
||||
---
|
||||
// Test width overflow.
|
||||
// Test required height overflowing page.
|
||||
#page(width: 100pt, height: 75pt)
|
||||
#square(fill: conifer)[
|
||||
But, soft! what light through yonder window breaks?
|
||||
|
@ -1,23 +1,23 @@
|
||||
// Test grid layouts.
|
||||
|
||||
---
|
||||
#let rect(width, fill) = rect(width: width, height: 2cm, fill: fill)
|
||||
#let cell(width, color) = rect(width: width, height: 2cm, fill: color)
|
||||
|
||||
#page(width: 100pt, height: 140pt)
|
||||
#grid(
|
||||
columns: (auto, 1fr, 3fr, 0.25cm, 3%, 2mm + 10%),
|
||||
rect(0.5cm, rgb("2a631a")),
|
||||
rect(100%, forest),
|
||||
rect(100%, conifer),
|
||||
rect(100%, rgb("ff0000")),
|
||||
rect(100%, rgb("00ff00")),
|
||||
rect(80%, rgb("00faf0")),
|
||||
rect(1cm, rgb("00ff00")),
|
||||
rect(0.5cm, rgb("2a631a")),
|
||||
rect(100%, forest),
|
||||
rect(100%, conifer),
|
||||
rect(100%, rgb("ff0000")),
|
||||
rect(100%, rgb("00ff00")),
|
||||
cell(0.5cm, rgb("2a631a")),
|
||||
cell(100%, forest),
|
||||
cell(100%, conifer),
|
||||
cell(100%, rgb("ff0000")),
|
||||
cell(100%, rgb("00ff00")),
|
||||
cell(80%, rgb("00faf0")),
|
||||
cell(1cm, rgb("00ff00")),
|
||||
cell(0.5cm, rgb("2a631a")),
|
||||
cell(100%, forest),
|
||||
cell(100%, conifer),
|
||||
cell(100%, rgb("ff0000")),
|
||||
cell(100%, rgb("00ff00")),
|
||||
)
|
||||
|
||||
#grid()
|
||||
@ -51,6 +51,7 @@
|
||||
#grid(
|
||||
columns: (1fr,),
|
||||
rows: (1fr, auto, 2fr),
|
||||
[], rect(width: 100%)[A bit more to the top], [],
|
||||
[],
|
||||
box(width: 100%)[A bit more to the top],
|
||||
[],
|
||||
)
|
||||
|
||||
|