mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
2d alignments with plus operator
This commit is contained in:
parent
d3f6040ced
commit
4f9e5819bb
@ -422,7 +422,7 @@ impl Eval for CallArgs {
|
|||||||
}
|
}
|
||||||
v => {
|
v => {
|
||||||
if let Value::Dyn(dynamic) = &v {
|
if let Value::Dyn(dynamic) = &v {
|
||||||
if let Some(args) = dynamic.downcast_ref::<Args>() {
|
if let Some(args) = dynamic.downcast::<Args>() {
|
||||||
items.extend(args.items.iter().cloned());
|
items.extend(args.items.iter().cloned());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use super::Value;
|
use super::{Dynamic, Value};
|
||||||
use crate::diag::StrResult;
|
use crate::diag::StrResult;
|
||||||
|
use crate::geom::{Align, Get, Spec};
|
||||||
use crate::util::EcoString;
|
use crate::util::EcoString;
|
||||||
use Value::*;
|
use Value::*;
|
||||||
|
|
||||||
@ -87,7 +88,25 @@ pub fn add(lhs: Value, rhs: Value) -> StrResult<Value> {
|
|||||||
(Template(a), Str(b)) => Template(a + b),
|
(Template(a), Str(b)) => Template(a + b),
|
||||||
(Str(a), Template(b)) => Template(a + b),
|
(Str(a), Template(b)) => Template(a + b),
|
||||||
|
|
||||||
(a, b) => mismatch!("cannot add {} and {}", a, b),
|
(a, b) => {
|
||||||
|
if let (Dyn(a), Dyn(b)) = (&a, &b) {
|
||||||
|
// 1D alignments can be summed into 2D alignments.
|
||||||
|
if let (Some(&a), Some(&b)) =
|
||||||
|
(a.downcast::<Align>(), b.downcast::<Align>())
|
||||||
|
{
|
||||||
|
if a.axis() == b.axis() {
|
||||||
|
return Err(format!("cannot add two {:?} alignments", a.axis()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut aligns = Spec::default();
|
||||||
|
aligns.set(a.axis(), Some(a));
|
||||||
|
aligns.set(b.axis(), Some(b));
|
||||||
|
return Ok(Dyn(Dynamic::new(aligns)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mismatch!("cannot add {} and {}", a, b);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Try to downcast to a reference to a specific type.
|
/// Try to downcast to a reference to a specific type.
|
||||||
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
|
pub fn downcast<T: 'static>(&self) -> Option<&T> {
|
||||||
self.0.as_any().downcast_ref()
|
self.0.as_any().downcast_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dyn_eq(&self, other: &Dynamic) -> bool {
|
fn dyn_eq(&self, other: &Dynamic) -> bool {
|
||||||
if let Some(other) = other.downcast_ref::<Self>() {
|
if let Some(other) = other.downcast::<Self>() {
|
||||||
self == other
|
self == other
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -334,7 +334,7 @@ macro_rules! castable {
|
|||||||
let found = match value {
|
let found = match value {
|
||||||
$($pattern => return Ok($out),)*
|
$($pattern => return Ok($out),)*
|
||||||
$crate::eval::Value::Dyn(dynamic) => {
|
$crate::eval::Value::Dyn(dynamic) => {
|
||||||
$(if let Some($dyn_in) = dynamic.downcast_ref::<$dyn_type>() {
|
$(if let Some($dyn_in) = dynamic.downcast::<$dyn_type>() {
|
||||||
return Ok($dyn_out);
|
return Ok($dyn_out);
|
||||||
})*
|
})*
|
||||||
dynamic.type_name()
|
dynamic.type_name()
|
||||||
|
@ -123,7 +123,7 @@ impl<T: Debug> Debug for Spec<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The two specific layouting axes.
|
/// The two specific layouting axes.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum SpecAxis {
|
pub enum SpecAxis {
|
||||||
/// The horizontal layouting axis.
|
/// The horizontal layouting axis.
|
||||||
Horizontal,
|
Horizontal,
|
||||||
@ -150,3 +150,12 @@ impl SpecAxis {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for SpecAxis {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
f.pad(match self {
|
||||||
|
Self::Horizontal => "horizontal",
|
||||||
|
Self::Vertical => "vertical",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -104,27 +104,27 @@ impl PackedNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Force a size for this node.
|
/// Force a size for this node.
|
||||||
pub fn sized(self, w: Option<Linear>, h: Option<Linear>) -> Self {
|
pub fn sized(self, sizing: Spec<Option<Linear>>) -> Self {
|
||||||
if w.is_some() || h.is_some() {
|
if sizing.any(Option::is_some) {
|
||||||
SizedNode { child: self, sizing: Spec::new(w, h) }.pack()
|
SizedNode { child: self, sizing }.pack()
|
||||||
} else {
|
} else {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set alignments for this node.
|
/// Set alignments for this node.
|
||||||
pub fn aligned(self, x: Option<Align>, y: Option<Align>) -> Self {
|
pub fn aligned(self, aligns: Spec<Option<Align>>) -> Self {
|
||||||
if x.is_some() || y.is_some() {
|
if aligns.any(Option::is_some) {
|
||||||
AlignNode { child: self, aligns: Spec::new(x, y) }.pack()
|
AlignNode { child: self, aligns }.pack()
|
||||||
} else {
|
} else {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move this node's contents without affecting layout.
|
/// Move this node's contents without affecting layout.
|
||||||
pub fn moved(self, dx: Option<Linear>, dy: Option<Linear>) -> Self {
|
pub fn moved(self, offset: Spec<Option<Linear>>) -> Self {
|
||||||
if dx.is_some() || dy.is_some() {
|
if offset.any(Option::is_some) {
|
||||||
MoveNode { child: self, offset: Spec::new(dx, dy) }.pack()
|
MoveNode { child: self, offset }.pack()
|
||||||
} else {
|
} else {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -2,32 +2,18 @@ use super::prelude::*;
|
|||||||
|
|
||||||
/// `align`: Configure the alignment along the layouting axes.
|
/// `align`: Configure the alignment along the layouting axes.
|
||||||
pub fn align(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn align(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
let Spec { x, y } = parse_aligns(args)?;
|
let aligns = args.expect::<Spec<_>>("alignment")?;
|
||||||
let body = args.expect::<Template>("body")?;
|
let body = args.expect::<Template>("body")?;
|
||||||
Ok(Value::Template(Template::from_block(move |style| {
|
Ok(Value::Template(Template::from_block(move |style| {
|
||||||
let mut style = style.clone();
|
let mut style = style.clone();
|
||||||
if let Some(x) = x {
|
if let Some(x) = aligns.x {
|
||||||
style.par_mut().align = x;
|
style.par_mut().align = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.pack(&style).aligned(x, y)
|
body.pack(&style).aligned(aligns)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse alignment arguments with shorthand.
|
|
||||||
pub(super) fn parse_aligns(args: &mut Args) -> TypResult<Spec<Option<Align>>> {
|
|
||||||
let mut x = args.named("horizontal")?;
|
|
||||||
let mut y = args.named("vertical")?;
|
|
||||||
for Spanned { v, span } in args.all::<Spanned<Align>>() {
|
|
||||||
match v.axis() {
|
|
||||||
SpecAxis::Horizontal if x.is_none() => x = Some(v),
|
|
||||||
SpecAxis::Vertical if y.is_none() => y = Some(v),
|
|
||||||
_ => bail!(span, "unexpected argument"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Spec::new(x, y))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A node that aligns its child.
|
/// A node that aligns its child.
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
pub struct AlignNode {
|
pub struct AlignNode {
|
||||||
|
@ -7,8 +7,7 @@ use crate::image::ImageId;
|
|||||||
/// `image`: An image.
|
/// `image`: An image.
|
||||||
pub fn image(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn image(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
let path = args.expect::<Spanned<EcoString>>("path to image file")?;
|
let path = args.expect::<Spanned<EcoString>>("path to image file")?;
|
||||||
let width = args.named("width")?;
|
let sizing = Spec::new(args.named("width")?, args.named("height")?);
|
||||||
let height = args.named("height")?;
|
|
||||||
let fit = args.named("fit")?.unwrap_or_default();
|
let fit = args.named("fit")?.unwrap_or_default();
|
||||||
|
|
||||||
// Load the image.
|
// Load the image.
|
||||||
@ -21,7 +20,7 @@ pub fn image(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(Value::Template(Template::from_inline(move |_| {
|
Ok(Value::Template(Template::from_inline(move |_| {
|
||||||
ImageNode { id, fit }.pack().sized(width, height)
|
ImageNode { id, fit }.pack().sized(sizing)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +141,15 @@ dynamic! {
|
|||||||
Align: "alignment",
|
Align: "alignment",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dynamic! {
|
||||||
|
Spec<Option<Align>>: "2d alignment",
|
||||||
|
@align: Align => {
|
||||||
|
let mut aligns = Spec::default();
|
||||||
|
aligns.set(align.axis(), Some(*align));
|
||||||
|
aligns
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
dynamic! {
|
dynamic! {
|
||||||
FontFamily: "font family",
|
FontFamily: "font family",
|
||||||
Value::Str(string) => Self::Named(string.to_lowercase()),
|
Value::Str(string) => Self::Named(string.to_lowercase()),
|
||||||
|
@ -24,20 +24,18 @@ pub fn par(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if let Some(Spanned { v, span }) = args.named::<Spanned<Dir>>("dir")? {
|
if let Some(Spanned { v, span }) = args.named::<Spanned<Dir>>("dir")? {
|
||||||
if v.axis() == SpecAxis::Horizontal {
|
if v.axis() != SpecAxis::Horizontal {
|
||||||
dir = Some(v);
|
|
||||||
} else {
|
|
||||||
bail!(span, "must be horizontal");
|
bail!(span, "must be horizontal");
|
||||||
}
|
}
|
||||||
|
dir = Some(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut align = None;
|
let mut align = None;
|
||||||
if let Some(Spanned { v, span }) = args.named::<Spanned<Align>>("align")? {
|
if let Some(Spanned { v, span }) = args.named::<Spanned<Align>>("align")? {
|
||||||
if v.axis() == SpecAxis::Horizontal {
|
if v.axis() != SpecAxis::Horizontal {
|
||||||
align = Some(v);
|
|
||||||
} else {
|
|
||||||
bail!(span, "must be horizontal");
|
bail!(span, "must be horizontal");
|
||||||
}
|
}
|
||||||
|
align = Some(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.template.modify(move |style| {
|
ctx.template.modify(move |style| {
|
||||||
|
@ -1,18 +1,13 @@
|
|||||||
use super::parse_aligns;
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
|
|
||||||
/// `place`: Place content at an absolute position.
|
/// `place`: Place content at an absolute position.
|
||||||
pub fn place(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn place(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
let Spec { x, y } = parse_aligns(args)?;
|
let aligns = args.find().unwrap_or(Spec::new(Some(Align::Left), None));
|
||||||
let dx = args.named("dx")?;
|
let offset = Spec::new(args.named("dx")?, args.named("dy")?);
|
||||||
let dy = args.named("dy")?;
|
|
||||||
let body: Template = args.expect("body")?;
|
let body: Template = args.expect("body")?;
|
||||||
Ok(Value::Template(Template::from_block(move |style| {
|
Ok(Value::Template(Template::from_block(move |style| {
|
||||||
PlacedNode {
|
PlacedNode {
|
||||||
child: body
|
child: body.pack(style).moved(offset).aligned(aligns),
|
||||||
.pack(style)
|
|
||||||
.moved(dx, dy)
|
|
||||||
.aligned(Some(x.unwrap_or(Align::Left)), y),
|
|
||||||
}
|
}
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,8 @@ use crate::util::RcExt;
|
|||||||
|
|
||||||
/// `rect`: A rectangle with optional content.
|
/// `rect`: A rectangle with optional content.
|
||||||
pub fn rect(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn rect(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
let width = args.named("width")?;
|
let sizing = Spec::new(args.named("width")?, args.named("height")?);
|
||||||
let height = args.named("height")?;
|
shape_impl(args, ShapeKind::Rect, sizing)
|
||||||
shape_impl(args, ShapeKind::Rect, width, height)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `square`: A square with optional content.
|
/// `square`: A square with optional content.
|
||||||
@ -21,14 +20,14 @@ pub fn square(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
None => args.named("height")?,
|
None => args.named("height")?,
|
||||||
size => size,
|
size => size,
|
||||||
};
|
};
|
||||||
shape_impl(args, ShapeKind::Square, width, height)
|
let sizing = Spec::new(width, height);
|
||||||
|
shape_impl(args, ShapeKind::Square, sizing)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `ellipse`: An ellipse with optional content.
|
/// `ellipse`: An ellipse with optional content.
|
||||||
pub fn ellipse(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn ellipse(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
let width = args.named("width")?;
|
let sizing = Spec::new(args.named("width")?, args.named("height")?);
|
||||||
let height = args.named("height")?;
|
shape_impl(args, ShapeKind::Ellipse, sizing)
|
||||||
shape_impl(args, ShapeKind::Ellipse, width, height)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `circle`: A circle with optional content.
|
/// `circle`: A circle with optional content.
|
||||||
@ -42,14 +41,14 @@ pub fn circle(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
None => args.named("height")?,
|
None => args.named("height")?,
|
||||||
diameter => diameter,
|
diameter => diameter,
|
||||||
};
|
};
|
||||||
shape_impl(args, ShapeKind::Circle, width, height)
|
let sizing = Spec::new(width, height);
|
||||||
|
shape_impl(args, ShapeKind::Circle, sizing)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shape_impl(
|
fn shape_impl(
|
||||||
args: &mut Args,
|
args: &mut Args,
|
||||||
kind: ShapeKind,
|
kind: ShapeKind,
|
||||||
width: Option<Linear>,
|
sizing: Spec<Option<Linear>>,
|
||||||
height: Option<Linear>,
|
|
||||||
) -> TypResult<Value> {
|
) -> TypResult<Value> {
|
||||||
// The default appearance of a shape.
|
// The default appearance of a shape.
|
||||||
let default = Stroke {
|
let default = Stroke {
|
||||||
@ -67,7 +66,10 @@ fn shape_impl(
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Shorthand for padding.
|
||||||
let padding = Sides::splat(args.named("padding")?.unwrap_or_default());
|
let padding = Sides::splat(args.named("padding")?.unwrap_or_default());
|
||||||
|
|
||||||
|
// The shape's contents.
|
||||||
let body = args.find::<Template>();
|
let body = args.find::<Template>();
|
||||||
|
|
||||||
Ok(Value::Template(Template::from_inline(move |style| {
|
Ok(Value::Template(Template::from_inline(move |style| {
|
||||||
@ -78,7 +80,7 @@ fn shape_impl(
|
|||||||
child: body.as_ref().map(|body| body.pack(style).padded(padding)),
|
child: body.as_ref().map(|body| body.pack(style).padded(padding)),
|
||||||
}
|
}
|
||||||
.pack()
|
.pack()
|
||||||
.sized(width, height)
|
.sized(sizing)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,21 +2,19 @@ use super::prelude::*;
|
|||||||
|
|
||||||
/// `box`: Size content and place it into a paragraph.
|
/// `box`: Size content and place it into a paragraph.
|
||||||
pub fn box_(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn box_(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
let width = args.named("width")?;
|
let sizing = Spec::new(args.named("width")?, args.named("height")?);
|
||||||
let height = args.named("height")?;
|
|
||||||
let body: Template = args.find().unwrap_or_default();
|
let body: Template = args.find().unwrap_or_default();
|
||||||
Ok(Value::Template(Template::from_inline(move |style| {
|
Ok(Value::Template(Template::from_inline(move |style| {
|
||||||
body.pack(style).sized(width, height)
|
body.pack(style).sized(sizing)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `block`: Size content and place it into the flow.
|
/// `block`: Size content and place it into the flow.
|
||||||
pub fn block(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn block(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
let width = args.named("width")?;
|
let sizing = Spec::new(args.named("width")?, args.named("height")?);
|
||||||
let height = args.named("height")?;
|
|
||||||
let body: Template = args.find().unwrap_or_default();
|
let body: Template = args.find().unwrap_or_default();
|
||||||
Ok(Value::Template(Template::from_block(move |style| {
|
Ok(Value::Template(Template::from_block(move |style| {
|
||||||
body.pack(style).sized(width, height)
|
body.pack(style).sized(sizing)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,10 @@ use super::prelude::*;
|
|||||||
|
|
||||||
/// `move`: Move content without affecting layout.
|
/// `move`: Move content without affecting layout.
|
||||||
pub fn move_(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn move_(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
let dx = args.named("dx")?;
|
let offset = Spec::new(args.named("x")?, args.named("y")?);
|
||||||
let dy = args.named("dy")?;
|
|
||||||
let body: Template = args.expect("body")?;
|
let body: Template = args.expect("body")?;
|
||||||
Ok(Value::Template(Template::from_inline(move |style| {
|
Ok(Value::Template(Template::from_inline(move |style| {
|
||||||
body.pack(style).moved(dx, dy)
|
body.pack(style).moved(offset)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,12 +10,12 @@
|
|||||||
|
|
||||||
Auto-sized circle. \
|
Auto-sized circle. \
|
||||||
#circle(fill: rgb("eb5278"), thickness: 2pt,
|
#circle(fill: rgb("eb5278"), thickness: 2pt,
|
||||||
align(center, horizon)[But, soft!]
|
align(center + horizon)[But, soft!]
|
||||||
)
|
)
|
||||||
|
|
||||||
Center-aligned rect in auto-sized circle.
|
Center-aligned rect in auto-sized circle.
|
||||||
#circle(fill: forest, stroke: conifer,
|
#circle(fill: forest, stroke: conifer,
|
||||||
align(center, horizon,
|
align(center + horizon,
|
||||||
rect(fill: conifer, pad(5pt)[But, soft!])
|
rect(fill: conifer, pad(5pt)[But, soft!])
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -37,7 +37,7 @@ Expanded by height.
|
|||||||
|
|
||||||
---
|
---
|
||||||
// Test relative sizing.
|
// Test relative sizing.
|
||||||
#let centered(body) = align(center, horizon, body)
|
#let centered(body) = align(center + horizon, body)
|
||||||
#font(fill: white)
|
#font(fill: white)
|
||||||
#rect(width: 100pt, height: 50pt, fill: rgb("aaa"), centered[
|
#rect(width: 100pt, height: 50pt, fill: rgb("aaa"), centered[
|
||||||
#circle(radius: 10pt, fill: eastern, centered[A]) // D=20pt
|
#circle(radius: 10pt, fill: eastern, centered[A]) // D=20pt
|
||||||
|
@ -9,7 +9,7 @@ Rect in ellipse in fixed rect. \
|
|||||||
#rect(width: 3cm, height: 2cm, fill: rgb("2a631a"),
|
#rect(width: 3cm, height: 2cm, fill: rgb("2a631a"),
|
||||||
ellipse(fill: forest,
|
ellipse(fill: forest,
|
||||||
rect(fill: conifer,
|
rect(fill: conifer,
|
||||||
align(center, horizon)[
|
align(center + horizon)[
|
||||||
Stuff inside an ellipse!
|
Stuff inside an ellipse!
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
#image("../../res/tiger.jpg", width: 100%, height: 20pt, fit: "stretch")
|
#image("../../res/tiger.jpg", width: 100%, height: 20pt, fit: "stretch")
|
||||||
|
|
||||||
// Make sure the bounding-box of the image is correct.
|
// Make sure the bounding-box of the image is correct.
|
||||||
#align(bottom, right, image("../../res/tiger.jpg", width: 40pt))
|
#align(bottom + right, image("../../res/tiger.jpg", width: 40pt))
|
||||||
|
|
||||||
---
|
---
|
||||||
// Test all three fit modes.
|
// Test all three fit modes.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
align(center, square(size: 20pt, fill: eastern)),
|
align(center, square(size: 20pt, fill: eastern)),
|
||||||
align(right, square(size: 15pt, fill: eastern)),
|
align(right, square(size: 15pt, fill: eastern)),
|
||||||
)
|
)
|
||||||
#align(center, horizon, rect(fill: eastern, height: 10pt))
|
#align(center + horizon, rect(fill: eastern, height: 10pt))
|
||||||
#align(bottom, stack(
|
#align(bottom, stack(
|
||||||
align(center, rect(fill: conifer, height: 10pt)),
|
align(center, rect(fill: conifer, height: 10pt)),
|
||||||
rect(fill: forest, height: 10pt),
|
rect(fill: forest, height: 10pt),
|
||||||
@ -19,3 +19,17 @@
|
|||||||
|
|
||||||
Dolor
|
Dolor
|
||||||
]
|
]
|
||||||
|
|
||||||
|
---
|
||||||
|
// Ref: false
|
||||||
|
#test(type(center), "alignment")
|
||||||
|
#test(type(horizon), "alignment")
|
||||||
|
#test(type(center + horizon), "2d alignment")
|
||||||
|
|
||||||
|
---
|
||||||
|
// Error: 8-22 cannot add two horizontal alignments
|
||||||
|
#align(center + right, [A])
|
||||||
|
|
||||||
|
---
|
||||||
|
// Error: 8-20 cannot add two vertical alignments
|
||||||
|
#align(top + bottom, [A])
|
||||||
|
@ -13,6 +13,6 @@
|
|||||||
height: 100% + 20pt,
|
height: 100% + 20pt,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
#align(bottom, right)[
|
#align(bottom + right)[
|
||||||
_Welcome to_ #underline[*Tigerland*]
|
_Welcome to_ #underline[*Tigerland*]
|
||||||
]
|
]
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#let tex = [{
|
#let tex = [{
|
||||||
[T]
|
[T]
|
||||||
h(-0.14 * size)
|
h(-0.14 * size)
|
||||||
move(dy: 0.22 * size)[E]
|
move(y: 0.22 * size)[E]
|
||||||
h(-0.12 * size)
|
h(-0.12 * size)
|
||||||
[X]
|
[X]
|
||||||
}]
|
}]
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
// Set all margins at once.
|
// Set all margins at once.
|
||||||
[
|
[
|
||||||
#page(margins: 5pt)
|
#page(margins: 5pt)
|
||||||
#place(top, left)[TL]
|
#place(top + left)[TL]
|
||||||
#place(bottom, right)[BR]
|
#place(bottom + right)[BR]
|
||||||
]
|
]
|
||||||
|
|
||||||
// Set individual margins.
|
// Set individual margins.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#page("a8")
|
#page("a8")
|
||||||
#place(bottom, center)[© Typst]
|
#place(bottom + center)[© Typst]
|
||||||
|
|
||||||
= Placement
|
= Placement
|
||||||
#place(right, image("../../res/tiger.jpg", width: 1.8cm))
|
#place(right, image("../../res/tiger.jpg", width: 1.8cm))
|
||||||
|
@ -15,3 +15,7 @@ It is the east, and Juliet is the sun.
|
|||||||
---
|
---
|
||||||
// Error: 13-16 must be horizontal
|
// Error: 13-16 must be horizontal
|
||||||
#par(align: top)
|
#par(align: top)
|
||||||
|
|
||||||
|
---
|
||||||
|
// Error: 13-29 expected alignment, found 2d alignment
|
||||||
|
#par(align: horizon + center)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user