Make Relative
generic
This commit is contained in:
parent
1192132dc0
commit
4bb6240b40
@ -8,7 +8,9 @@ use std::sync::Arc;
|
||||
use super::{Barrier, StyleChain};
|
||||
use crate::diag::TypResult;
|
||||
use crate::frame::{Element, Frame, Geometry, Shape, Stroke};
|
||||
use crate::geom::{Align, Length, Paint, Point, Relative, Sides, Size, Spec, Transform};
|
||||
use crate::geom::{
|
||||
Align, Length, Numeric, Paint, Point, Relative, Sides, Size, Spec, Transform,
|
||||
};
|
||||
use crate::library::graphics::MoveNode;
|
||||
use crate::library::layout::{AlignNode, PadNode};
|
||||
use crate::util::Prehashed;
|
||||
@ -161,7 +163,7 @@ impl LayoutNode {
|
||||
}
|
||||
|
||||
/// Force a size for this node.
|
||||
pub fn sized(self, sizing: Spec<Option<Relative>>) -> Self {
|
||||
pub fn sized(self, sizing: Spec<Option<Relative<Length>>>) -> Self {
|
||||
if sizing.any(Option::is_some) {
|
||||
SizedNode { sizing, child: self }.pack()
|
||||
} else {
|
||||
@ -189,7 +191,7 @@ impl LayoutNode {
|
||||
}
|
||||
|
||||
/// Pad this node at the sides.
|
||||
pub fn padded(self, padding: Sides<Relative>) -> Self {
|
||||
pub fn padded(self, padding: Sides<Relative<Length>>) -> Self {
|
||||
if !padding.left.is_zero()
|
||||
|| !padding.top.is_zero()
|
||||
|| !padding.right.is_zero()
|
||||
@ -205,7 +207,7 @@ impl LayoutNode {
|
||||
pub fn moved(self, offset: Point) -> Self {
|
||||
if !offset.is_zero() {
|
||||
MoveNode {
|
||||
transform: Transform::translation(offset.x, offset.y),
|
||||
transform: Transform::translate(offset.x, offset.y),
|
||||
child: self,
|
||||
}
|
||||
.pack()
|
||||
@ -292,7 +294,7 @@ impl Layout for EmptyNode {
|
||||
#[derive(Debug, Hash)]
|
||||
struct SizedNode {
|
||||
/// How to size the node horizontally and vertically.
|
||||
sizing: Spec<Option<Relative>>,
|
||||
sizing: Spec<Option<Relative<Length>>>,
|
||||
/// The node to be sized.
|
||||
child: LayoutNode,
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use std::cmp::Ordering;
|
||||
|
||||
use super::{Dynamic, StrExt, Value};
|
||||
use crate::diag::StrResult;
|
||||
use crate::geom::{Align, Spec, SpecAxis};
|
||||
use crate::geom::{Align, Numeric, Spec, SpecAxis};
|
||||
use Value::*;
|
||||
|
||||
/// Bail with a type mismatch error.
|
||||
@ -66,12 +66,12 @@ pub fn add(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
(Angle(a), Angle(b)) => Angle(a + b),
|
||||
|
||||
(Length(a), Length(b)) => Length(a + b),
|
||||
(Length(a), Ratio(b)) => Relative(a + b),
|
||||
(Length(a), Relative(b)) => Relative(a + b),
|
||||
(Length(a), Ratio(b)) => Relative(b + a),
|
||||
(Length(a), Relative(b)) => Relative(b + a),
|
||||
|
||||
(Ratio(a), Length(b)) => Relative(a + b),
|
||||
(Ratio(a), Ratio(b)) => Ratio(a + b),
|
||||
(Ratio(a), Relative(b)) => Relative(a + b),
|
||||
(Ratio(a), Relative(b)) => Relative(b + a),
|
||||
|
||||
(Relative(a), Length(b)) => Relative(a + b),
|
||||
(Relative(a), Ratio(b)) => Relative(a + b),
|
||||
@ -123,15 +123,15 @@ pub fn sub(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
(Angle(a), Angle(b)) => Angle(a - b),
|
||||
|
||||
(Length(a), Length(b)) => Length(a - b),
|
||||
(Length(a), Ratio(b)) => Relative(a - b),
|
||||
(Length(a), Relative(b)) => Relative(a - b),
|
||||
(Length(a), Ratio(b)) => Relative(-b + a),
|
||||
(Length(a), Relative(b)) => Relative(-b + a),
|
||||
|
||||
(Ratio(a), Length(b)) => Relative(a - b),
|
||||
(Ratio(a), Length(b)) => Relative(a + -b),
|
||||
(Ratio(a), Ratio(b)) => Ratio(a - b),
|
||||
(Ratio(a), Relative(b)) => Relative(a - b),
|
||||
(Ratio(a), Relative(b)) => Relative(-b + a),
|
||||
|
||||
(Relative(a), Length(b)) => Relative(a - b),
|
||||
(Relative(a), Ratio(b)) => Relative(a - b),
|
||||
(Relative(a), Length(b)) => Relative(a + -b),
|
||||
(Relative(a), Ratio(b)) => Relative(a + -b),
|
||||
(Relative(a), Relative(b)) => Relative(a - b),
|
||||
|
||||
(Fraction(a), Fraction(b)) => Fraction(a - b),
|
||||
|
@ -31,7 +31,7 @@ pub enum Value {
|
||||
/// A ratio: `50%`.
|
||||
Ratio(Ratio),
|
||||
/// A relative length, combination of a ratio and a length: `20% + 5cm`.
|
||||
Relative(Relative),
|
||||
Relative(Relative<Length>),
|
||||
/// A fraction: `1fr`.
|
||||
Fraction(Fraction),
|
||||
/// A color value: `#f79143ff`.
|
||||
@ -549,7 +549,7 @@ primitive! { f64: "float", Float, Int(v) => v as f64 }
|
||||
primitive! { Length: "length", Length }
|
||||
primitive! { Angle: "angle", Angle }
|
||||
primitive! { Ratio: "ratio", Ratio }
|
||||
primitive! { Relative: "relative length", Relative, Length(v) => v.into(), Ratio(v) => v.into() }
|
||||
primitive! { Relative<Length>: "relative length", Relative, Length(v) => v.into(), Ratio(v) => v.into() }
|
||||
primitive! { Fraction: "fraction", Fraction }
|
||||
primitive! { Color: "color", Color }
|
||||
primitive! { EcoString: "string", Str }
|
||||
|
@ -17,7 +17,7 @@ use ttf_parser::{name_id, GlyphId, Tag};
|
||||
use super::subset::subset;
|
||||
use crate::font::{find_name, FaceId, FontStore};
|
||||
use crate::frame::{Element, Frame, Geometry, Group, Shape, Stroke, Text};
|
||||
use crate::geom::{self, Color, Em, Length, Paint, Point, Size, Transform};
|
||||
use crate::geom::{self, Color, Em, Length, Numeric, Paint, Point, Size, Transform};
|
||||
use crate::image::{Image, ImageId, ImageStore, RasterImage};
|
||||
use crate::Context;
|
||||
|
||||
@ -423,7 +423,7 @@ impl<'a> PageExporter<'a> {
|
||||
}
|
||||
|
||||
fn write_group(&mut self, pos: Point, group: &Group) {
|
||||
let translation = Transform::translation(pos.x, pos.y);
|
||||
let translation = Transform::translate(pos.x, pos.y);
|
||||
|
||||
self.save_state();
|
||||
self.transform(translation.pre_concat(group.transform));
|
||||
|
@ -415,7 +415,7 @@ pub enum VerticalFontMetric {
|
||||
Descender,
|
||||
/// An font-size dependent distance from the baseline (positive goes up, negative
|
||||
/// down).
|
||||
Relative(Relative),
|
||||
Relative(Relative<Length>),
|
||||
}
|
||||
|
||||
/// Properties of a single font face.
|
||||
|
@ -4,7 +4,9 @@ use std::fmt::{self, Debug, Formatter};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::font::FaceId;
|
||||
use crate::geom::{Align, Em, Length, Paint, Path, Point, Size, Spec, Transform};
|
||||
use crate::geom::{
|
||||
Align, Em, Length, Numeric, Paint, Path, Point, Size, Spec, Transform,
|
||||
};
|
||||
use crate::image::ImageId;
|
||||
|
||||
/// A finished layout with elements at fixed positions.
|
||||
|
@ -10,6 +10,16 @@ impl Angle {
|
||||
Self(Scalar(0.0))
|
||||
}
|
||||
|
||||
/// Create an angle from a number of raw units.
|
||||
pub const fn raw(raw: f64) -> Self {
|
||||
Self(Scalar(raw))
|
||||
}
|
||||
|
||||
/// Create an angle from a value in a unit.
|
||||
pub fn with_unit(val: f64, unit: AngularUnit) -> Self {
|
||||
Self(Scalar(val * unit.raw_scale()))
|
||||
}
|
||||
|
||||
/// Create an angle from a number of radians.
|
||||
pub fn rad(rad: f64) -> Self {
|
||||
Self::with_unit(rad, AngularUnit::Rad)
|
||||
@ -20,9 +30,14 @@ impl Angle {
|
||||
Self::with_unit(deg, AngularUnit::Deg)
|
||||
}
|
||||
|
||||
/// Create an angle from a number of raw units.
|
||||
pub const fn raw(raw: f64) -> Self {
|
||||
Self(Scalar(raw))
|
||||
/// Get the value of this angle in raw units.
|
||||
pub const fn to_raw(self) -> f64 {
|
||||
(self.0).0
|
||||
}
|
||||
|
||||
/// Get the value of this length in unit.
|
||||
pub fn to_unit(self, unit: AngularUnit) -> f64 {
|
||||
self.to_raw() / unit.raw_scale()
|
||||
}
|
||||
|
||||
/// Convert this to a number of radians.
|
||||
@ -35,9 +50,9 @@ impl Angle {
|
||||
self.to_unit(AngularUnit::Deg)
|
||||
}
|
||||
|
||||
/// Get the value of this angle in raw units.
|
||||
pub const fn to_raw(self) -> f64 {
|
||||
(self.0).0
|
||||
/// The absolute value of the this angle.
|
||||
pub fn abs(self) -> Self {
|
||||
Self::raw(self.to_raw().abs())
|
||||
}
|
||||
|
||||
/// Get the sine of this angle in radians.
|
||||
@ -49,20 +64,15 @@ impl Angle {
|
||||
pub fn cos(self) -> f64 {
|
||||
self.to_rad().cos()
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an angle from a value in a unit.
|
||||
pub fn with_unit(val: f64, unit: AngularUnit) -> Self {
|
||||
Self(Scalar(val * unit.raw_scale()))
|
||||
impl Numeric for Angle {
|
||||
fn zero() -> Self {
|
||||
Self::zero()
|
||||
}
|
||||
|
||||
/// Get the value of this length in unit.
|
||||
pub fn to_unit(self, unit: AngularUnit) -> f64 {
|
||||
self.to_raw() / unit.raw_scale()
|
||||
}
|
||||
|
||||
/// The absolute value of the this angle.
|
||||
pub fn abs(self) -> Self {
|
||||
Self::raw(self.to_raw().abs())
|
||||
fn is_finite(self) -> bool {
|
||||
self.0.is_finite()
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,6 +142,7 @@ impl Sum for Angle {
|
||||
Self(iter.map(|s| s.0).sum())
|
||||
}
|
||||
}
|
||||
|
||||
/// Different units of angular measurement.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum AngularUnit {
|
||||
|
@ -32,19 +32,24 @@ impl Em {
|
||||
Self(Scalar(length / font_size))
|
||||
}
|
||||
|
||||
/// Convert to a length at the given font size.
|
||||
pub fn resolve(self, font_size: Length) -> Length {
|
||||
self.get() * font_size
|
||||
}
|
||||
|
||||
/// The number of em units.
|
||||
pub const fn get(self) -> f64 {
|
||||
(self.0).0
|
||||
}
|
||||
|
||||
/// Whether the length is zero.
|
||||
pub fn is_zero(self) -> bool {
|
||||
self.0 == 0.0
|
||||
/// Convert to a length at the given font size.
|
||||
pub fn resolve(self, font_size: Length) -> Length {
|
||||
self.get() * font_size
|
||||
}
|
||||
}
|
||||
|
||||
impl Numeric for Em {
|
||||
fn zero() -> Self {
|
||||
Self::zero()
|
||||
}
|
||||
|
||||
fn is_finite(self) -> bool {
|
||||
self.0.is_finite()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,11 +25,6 @@ impl Fraction {
|
||||
(self.0).0
|
||||
}
|
||||
|
||||
/// Whether the fraction is zero.
|
||||
pub fn is_zero(self) -> bool {
|
||||
self.0 == 0.0
|
||||
}
|
||||
|
||||
/// The absolute value of the this fraction.
|
||||
pub fn abs(self) -> Self {
|
||||
Self::new(self.get().abs())
|
||||
@ -46,6 +41,16 @@ impl Fraction {
|
||||
}
|
||||
}
|
||||
|
||||
impl Numeric for Fraction {
|
||||
fn zero() -> Self {
|
||||
Self::zero()
|
||||
}
|
||||
|
||||
fn is_finite(self) -> bool {
|
||||
self.0.is_finite()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Fraction {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}fr", round_2(self.get()))
|
||||
|
@ -15,6 +15,16 @@ impl Length {
|
||||
Self(Scalar(f64::INFINITY))
|
||||
}
|
||||
|
||||
/// Create a length from a number of raw units.
|
||||
pub const fn raw(raw: f64) -> Self {
|
||||
Self(Scalar(raw))
|
||||
}
|
||||
|
||||
/// Create a length from a value in a unit.
|
||||
pub fn with_unit(val: f64, unit: LengthUnit) -> Self {
|
||||
Self(Scalar(val * unit.raw_scale()))
|
||||
}
|
||||
|
||||
/// Create a length from a number of points.
|
||||
pub fn pt(pt: f64) -> Self {
|
||||
Self::with_unit(pt, LengthUnit::Pt)
|
||||
@ -35,9 +45,14 @@ impl Length {
|
||||
Self::with_unit(inches, LengthUnit::In)
|
||||
}
|
||||
|
||||
/// Create a length from a number of raw units.
|
||||
pub const fn raw(raw: f64) -> Self {
|
||||
Self(Scalar(raw))
|
||||
/// Get the value of this length in raw units.
|
||||
pub const fn to_raw(self) -> f64 {
|
||||
(self.0).0
|
||||
}
|
||||
|
||||
/// Get the value of this length in unit.
|
||||
pub fn to_unit(self, unit: LengthUnit) -> f64 {
|
||||
self.to_raw() / unit.raw_scale()
|
||||
}
|
||||
|
||||
/// Convert this to a number of points.
|
||||
@ -60,36 +75,6 @@ impl Length {
|
||||
self.to_unit(LengthUnit::In)
|
||||
}
|
||||
|
||||
/// Get the value of this length in raw units.
|
||||
pub const fn to_raw(self) -> f64 {
|
||||
(self.0).0
|
||||
}
|
||||
|
||||
/// Create a length from a value in a unit.
|
||||
pub fn with_unit(val: f64, unit: LengthUnit) -> Self {
|
||||
Self(Scalar(val * unit.raw_scale()))
|
||||
}
|
||||
|
||||
/// Get the value of this length in unit.
|
||||
pub fn to_unit(self, unit: LengthUnit) -> f64 {
|
||||
self.to_raw() / unit.raw_scale()
|
||||
}
|
||||
|
||||
/// Whether the length is zero.
|
||||
pub fn is_zero(self) -> bool {
|
||||
self.to_raw() == 0.0
|
||||
}
|
||||
|
||||
/// Whether the length is finite.
|
||||
pub fn is_finite(self) -> bool {
|
||||
self.to_raw().is_finite()
|
||||
}
|
||||
|
||||
/// Whether the length is infinite.
|
||||
pub fn is_infinite(self) -> bool {
|
||||
self.to_raw().is_infinite()
|
||||
}
|
||||
|
||||
/// The absolute value of the this length.
|
||||
pub fn abs(self) -> Self {
|
||||
Self::raw(self.to_raw().abs())
|
||||
@ -137,6 +122,16 @@ impl Length {
|
||||
}
|
||||
}
|
||||
|
||||
impl Numeric for Length {
|
||||
fn zero() -> Self {
|
||||
Self::zero()
|
||||
}
|
||||
|
||||
fn is_finite(self) -> bool {
|
||||
self.0.is_finite()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Length {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}pt", round_2(self.to_pt()))
|
||||
|
@ -60,6 +60,30 @@ pub trait Get<Index> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A numeric type.
|
||||
pub trait Numeric:
|
||||
Sized
|
||||
+ Debug
|
||||
+ Copy
|
||||
+ PartialEq
|
||||
+ Neg<Output = Self>
|
||||
+ Add<Output = Self>
|
||||
+ Sub<Output = Self>
|
||||
+ Mul<f64, Output = Self>
|
||||
+ Div<f64, Output = Self>
|
||||
{
|
||||
/// The identity element.
|
||||
fn zero() -> Self;
|
||||
|
||||
/// Whether `self` is the identity element.
|
||||
fn is_zero(self) -> bool {
|
||||
self == Self::zero()
|
||||
}
|
||||
|
||||
/// Whether `self` contains only finite parts.
|
||||
fn is_finite(self) -> bool;
|
||||
}
|
||||
|
||||
/// Round a float to two decimal places.
|
||||
fn round_2(value: f64) -> f64 {
|
||||
(value * 100.0).round() / 100.0
|
||||
|
@ -1,4 +1,3 @@
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
|
||||
use syntect::highlighting::Color as SynColor;
|
||||
@ -103,7 +102,7 @@ impl RgbaColor {
|
||||
}
|
||||
|
||||
impl FromStr for RgbaColor {
|
||||
type Err = RgbaError;
|
||||
type Err = &'static str;
|
||||
|
||||
/// Constructs a new color from hex strings like the following:
|
||||
/// - `#aef` (shorthand, with leading hashtag),
|
||||
@ -113,8 +112,8 @@ impl FromStr for RgbaColor {
|
||||
/// The hashtag is optional and both lower and upper case are fine.
|
||||
fn from_str(hex_str: &str) -> Result<Self, Self::Err> {
|
||||
let hex_str = hex_str.strip_prefix('#').unwrap_or(hex_str);
|
||||
if !hex_str.is_ascii() {
|
||||
return Err(RgbaError);
|
||||
if hex_str.chars().any(|c| !c.is_ascii_hexdigit()) {
|
||||
return Err("string contains non-hexadecimal letters");
|
||||
}
|
||||
|
||||
let len = hex_str.len();
|
||||
@ -123,7 +122,7 @@ impl FromStr for RgbaColor {
|
||||
let alpha = len == 4 || len == 8;
|
||||
|
||||
if !long && !short {
|
||||
return Err(RgbaError);
|
||||
return Err("string has wrong length");
|
||||
}
|
||||
|
||||
let mut values: [u8; 4] = [255; 4];
|
||||
@ -133,7 +132,7 @@ impl FromStr for RgbaColor {
|
||||
let pos = elem * item_len;
|
||||
|
||||
let item = &hex_str[pos .. (pos + item_len)];
|
||||
values[elem] = u8::from_str_radix(item, 16).map_err(|_| RgbaError)?;
|
||||
values[elem] = u8::from_str_radix(item, 16).unwrap();
|
||||
|
||||
if short {
|
||||
// Duplicate number for shorthand notation, i.e. `a` -> `aa`
|
||||
@ -169,18 +168,6 @@ impl Debug for RgbaColor {
|
||||
}
|
||||
}
|
||||
|
||||
/// The error when parsing an [`RgbaColor`] from a string fails.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct RgbaError;
|
||||
|
||||
impl Display for RgbaError {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
f.pad("invalid hex string")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for RgbaError {}
|
||||
|
||||
/// An 8-bit CMYK color.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct CmykColor {
|
||||
@ -268,13 +255,14 @@ mod tests {
|
||||
#[test]
|
||||
fn test_parse_invalid_colors() {
|
||||
#[track_caller]
|
||||
fn test(hex: &str) {
|
||||
assert_eq!(RgbaColor::from_str(hex), Err(RgbaError));
|
||||
fn test(hex: &str, message: &str) {
|
||||
assert_eq!(RgbaColor::from_str(hex), Err(message));
|
||||
}
|
||||
|
||||
test("12345");
|
||||
test("a5");
|
||||
test("14B2AH");
|
||||
test("f075ff011");
|
||||
test("a5", "string has wrong length");
|
||||
test("12345", "string has wrong length");
|
||||
test("f075ff011", "string has wrong length");
|
||||
test("hmmm", "string contains non-hexadecimal letters");
|
||||
test("14B2AH", "string contains non-hexadecimal letters");
|
||||
}
|
||||
}
|
||||
|
@ -35,17 +35,22 @@ impl Point {
|
||||
Self { x: Length::zero(), y }
|
||||
}
|
||||
|
||||
/// Whether both components are zero.
|
||||
pub fn is_zero(self) -> bool {
|
||||
self.x.is_zero() && self.y.is_zero()
|
||||
/// Transform the point with the given transformation.
|
||||
pub fn transform(self, ts: Transform) -> Self {
|
||||
Self::new(
|
||||
ts.sx.resolve(self.x) + ts.kx.resolve(self.y) + ts.tx,
|
||||
ts.ky.resolve(self.x) + ts.sy.resolve(self.y) + ts.ty,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Numeric for Point {
|
||||
fn zero() -> Self {
|
||||
Self::zero()
|
||||
}
|
||||
|
||||
/// Transform the point with the given transformation.
|
||||
pub fn transform(self, transform: Transform) -> Self {
|
||||
Self::new(
|
||||
transform.sx.resolve(self.x) + transform.kx.resolve(self.y) + transform.tx,
|
||||
transform.ky.resolve(self.x) + transform.sy.resolve(self.y) + transform.ty,
|
||||
)
|
||||
fn is_finite(self) -> bool {
|
||||
self.x.is_finite() && self.y.is_finite()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,16 +28,6 @@ impl Ratio {
|
||||
(self.0).0
|
||||
}
|
||||
|
||||
/// Resolve this relative to the given `length`.
|
||||
pub fn resolve(self, length: Length) -> Length {
|
||||
// We don't want NaNs.
|
||||
if length.is_infinite() {
|
||||
Length::zero()
|
||||
} else {
|
||||
self.get() * length
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the ratio is zero.
|
||||
pub fn is_zero(self) -> bool {
|
||||
self.0 == 0.0
|
||||
@ -52,6 +42,12 @@ impl Ratio {
|
||||
pub fn abs(self) -> Self {
|
||||
Self::new(self.get().abs())
|
||||
}
|
||||
|
||||
/// Resolve this relative to the given `whole`.
|
||||
pub fn resolve<T: Numeric>(self, whole: T) -> T {
|
||||
let resolved = whole * self.get();
|
||||
if resolved.is_finite() { resolved } else { T::zero() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Ratio {
|
||||
|
@ -1,65 +1,60 @@
|
||||
use super::*;
|
||||
|
||||
/// A relative length.
|
||||
/// A value that is composed of a relative and an absolute part.
|
||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Relative {
|
||||
pub struct Relative<T: Numeric> {
|
||||
/// The relative part.
|
||||
pub rel: Ratio,
|
||||
/// The absolute part.
|
||||
pub abs: Length,
|
||||
pub abs: T,
|
||||
}
|
||||
|
||||
impl Relative {
|
||||
/// The zero relative length.
|
||||
pub const fn zero() -> Self {
|
||||
Self { rel: Ratio::zero(), abs: Length::zero() }
|
||||
impl<T: Numeric> Relative<T> {
|
||||
/// The zero relative.
|
||||
pub fn zero() -> Self {
|
||||
Self { rel: Ratio::zero(), abs: T::zero() }
|
||||
}
|
||||
|
||||
/// A relative length with a ratio of `100%` and no absolute part.
|
||||
pub const fn one() -> Self {
|
||||
Self { rel: Ratio::one(), abs: Length::zero() }
|
||||
/// A relative with a ratio of `100%` and no absolute part.
|
||||
pub fn one() -> Self {
|
||||
Self { rel: Ratio::one(), abs: T::zero() }
|
||||
}
|
||||
|
||||
/// Create a new relative length from its parts.
|
||||
pub const fn new(rel: Ratio, abs: Length) -> Self {
|
||||
/// Create a new relative from its parts.
|
||||
pub fn new(rel: Ratio, abs: T) -> Self {
|
||||
Self { rel, abs }
|
||||
}
|
||||
|
||||
/// Resolve this length relative to the given `length`.
|
||||
pub fn resolve(self, length: Length) -> Length {
|
||||
self.rel.resolve(length) + self.abs
|
||||
}
|
||||
|
||||
/// Whether both parts are zero.
|
||||
pub fn is_zero(self) -> bool {
|
||||
self.rel.is_zero() && self.abs.is_zero()
|
||||
}
|
||||
|
||||
/// Whether there is a relative part.
|
||||
pub fn is_relative(self) -> bool {
|
||||
!self.rel.is_zero()
|
||||
/// Resolve this relative to the given `whole`.
|
||||
pub fn resolve(self, whole: T) -> T {
|
||||
self.rel.resolve(whole) + self.abs
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Relative {
|
||||
impl<T: Numeric> Debug for Relative<T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{:?} + {:?}", self.rel, self.abs)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Length> for Relative {
|
||||
fn from(abs: Length) -> Self {
|
||||
impl<T: Numeric> From<T> for Relative<T> {
|
||||
fn from(abs: T) -> Self {
|
||||
Self { rel: Ratio::zero(), abs }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Ratio> for Relative {
|
||||
impl<T: Numeric> From<Ratio> for Relative<T> {
|
||||
fn from(rel: Ratio) -> Self {
|
||||
Self { rel, abs: Length::zero() }
|
||||
Self { rel, abs: T::zero() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for Relative {
|
||||
impl<T: Numeric> Neg for Relative<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self {
|
||||
@ -67,10 +62,10 @@ impl Neg for Relative {
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Relative {
|
||||
impl<T: Numeric> Add for Relative<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: Self) -> Self {
|
||||
fn add(self, other: Self) -> Self::Output {
|
||||
Self {
|
||||
rel: self.rel + other.rel,
|
||||
abs: self.abs + other.abs,
|
||||
@ -78,66 +73,18 @@ impl Add for Relative {
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Ratio> for Length {
|
||||
type Output = Relative;
|
||||
|
||||
fn add(self, other: Ratio) -> Relative {
|
||||
Relative { rel: other, abs: self }
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Length> for Ratio {
|
||||
type Output = Relative;
|
||||
|
||||
fn add(self, other: Length) -> Relative {
|
||||
other + self
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Length> for Relative {
|
||||
impl<T: Numeric> Sub for Relative<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: Length) -> Self {
|
||||
Self { rel: self.rel, abs: self.abs + other }
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
self + -other
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Relative> for Length {
|
||||
type Output = Relative;
|
||||
|
||||
fn add(self, other: Relative) -> Relative {
|
||||
other + self
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Ratio> for Relative {
|
||||
impl<T: Numeric> Mul<f64> for Relative<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: Ratio) -> Self {
|
||||
Self { rel: self.rel + other, abs: self.abs }
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Relative> for Ratio {
|
||||
type Output = Relative;
|
||||
|
||||
fn add(self, other: Relative) -> Relative {
|
||||
other + self
|
||||
}
|
||||
}
|
||||
|
||||
sub_impl!(Relative - Relative -> Relative);
|
||||
sub_impl!(Length - Ratio -> Relative);
|
||||
sub_impl!(Ratio - Length -> Relative);
|
||||
sub_impl!(Relative - Length -> Relative);
|
||||
sub_impl!(Length - Relative -> Relative);
|
||||
sub_impl!(Relative - Ratio -> Relative);
|
||||
sub_impl!(Ratio - Relative -> Relative);
|
||||
|
||||
impl Mul<f64> for Relative {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, other: f64) -> Self {
|
||||
fn mul(self, other: f64) -> Self::Output {
|
||||
Self {
|
||||
rel: self.rel * other,
|
||||
abs: self.abs * other,
|
||||
@ -145,18 +92,18 @@ impl Mul<f64> for Relative {
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Relative> for f64 {
|
||||
type Output = Relative;
|
||||
impl<T: Numeric> Mul<Relative<T>> for f64 {
|
||||
type Output = Relative<T>;
|
||||
|
||||
fn mul(self, other: Relative) -> Relative {
|
||||
fn mul(self, other: Relative<T>) -> Self::Output {
|
||||
other * self
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<f64> for Relative {
|
||||
impl<T: Numeric> Div<f64> for Relative<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, other: f64) -> Self {
|
||||
fn div(self, other: f64) -> Self::Output {
|
||||
Self {
|
||||
rel: self.rel / other,
|
||||
abs: self.abs / other,
|
||||
@ -164,11 +111,50 @@ impl Div<f64> for Relative {
|
||||
}
|
||||
}
|
||||
|
||||
assign_impl!(Relative += Relative);
|
||||
assign_impl!(Relative += Length);
|
||||
assign_impl!(Relative += Ratio);
|
||||
assign_impl!(Relative -= Relative);
|
||||
assign_impl!(Relative -= Length);
|
||||
assign_impl!(Relative -= Ratio);
|
||||
assign_impl!(Relative *= f64);
|
||||
assign_impl!(Relative /= f64);
|
||||
impl<T: Numeric> AddAssign for Relative<T> {
|
||||
fn add_assign(&mut self, other: Self) {
|
||||
*self = *self + other;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Numeric> SubAssign for Relative<T> {
|
||||
fn sub_assign(&mut self, other: Self) {
|
||||
*self = *self - other;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Numeric> MulAssign<f64> for Relative<T> {
|
||||
fn mul_assign(&mut self, other: f64) {
|
||||
*self = *self * other;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Numeric> DivAssign<f64> for Relative<T> {
|
||||
fn div_assign(&mut self, other: f64) {
|
||||
*self = *self * other;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Numeric> Add<T> for Ratio {
|
||||
type Output = Relative<T>;
|
||||
|
||||
fn add(self, other: T) -> Self::Output {
|
||||
Relative::from(self) + Relative::from(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Numeric> Add<T> for Relative<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: T) -> Self::Output {
|
||||
self + Relative::from(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Numeric> Add<Ratio> for Relative<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: Ratio) -> Self::Output {
|
||||
self + Relative::from(other)
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,16 @@ use super::*;
|
||||
#[derive(Default, Copy, Clone)]
|
||||
pub struct Scalar(pub f64);
|
||||
|
||||
impl Numeric for Scalar {
|
||||
fn zero() -> Self {
|
||||
Self(0.0)
|
||||
}
|
||||
|
||||
fn is_finite(self) -> bool {
|
||||
self.0.is_finite()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Scalar {
|
||||
fn from(float: f64) -> Self {
|
||||
Self(float)
|
||||
|
@ -43,7 +43,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl Sides<Relative> {
|
||||
impl Sides<Relative<Length>> {
|
||||
/// Resolve the sides relative to the given `size`.
|
||||
pub fn resolve(self, size: Size) -> Sides<Length> {
|
||||
Sides {
|
||||
|
@ -201,7 +201,7 @@ pub type Size = Spec<Length>;
|
||||
|
||||
impl Size {
|
||||
/// The zero value.
|
||||
pub fn zero() -> Self {
|
||||
pub const fn zero() -> Self {
|
||||
Self { x: Length::zero(), y: Length::zero() }
|
||||
}
|
||||
|
||||
@ -210,27 +210,22 @@ impl Size {
|
||||
self.x.fits(other.x) && self.y.fits(other.y)
|
||||
}
|
||||
|
||||
/// Whether both components are zero.
|
||||
pub fn is_zero(self) -> bool {
|
||||
self.x.is_zero() && self.y.is_zero()
|
||||
}
|
||||
|
||||
/// Whether both components are finite.
|
||||
pub fn is_finite(self) -> bool {
|
||||
self.x.is_finite() && self.y.is_finite()
|
||||
}
|
||||
|
||||
/// Whether any of the two components is infinite.
|
||||
pub fn is_infinite(self) -> bool {
|
||||
self.x.is_infinite() || self.y.is_infinite()
|
||||
}
|
||||
|
||||
/// Convert to a point.
|
||||
pub fn to_point(self) -> Point {
|
||||
Point::new(self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
impl Numeric for Size {
|
||||
fn zero() -> Self {
|
||||
Self::zero()
|
||||
}
|
||||
|
||||
fn is_finite(self) -> bool {
|
||||
self.x.is_finite() && self.y.is_finite()
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for Size {
|
||||
type Output = Self;
|
||||
|
||||
|
@ -24,18 +24,18 @@ impl Transform {
|
||||
}
|
||||
}
|
||||
|
||||
/// A translation transform.
|
||||
pub const fn translation(tx: Length, ty: Length) -> Self {
|
||||
/// A translate transform.
|
||||
pub const fn translate(tx: Length, ty: Length) -> Self {
|
||||
Self { tx, ty, ..Self::identity() }
|
||||
}
|
||||
|
||||
/// A scaling transform.
|
||||
/// A scale transform.
|
||||
pub const fn scale(sx: Ratio, sy: Ratio) -> Self {
|
||||
Self { sx, sy, ..Self::identity() }
|
||||
}
|
||||
|
||||
/// A rotation transform.
|
||||
pub fn rotation(angle: Angle) -> Self {
|
||||
/// A rotate transform.
|
||||
pub fn rotate(angle: Angle) -> Self {
|
||||
let cos = Ratio::new(angle.cos());
|
||||
let sin = Ratio::new(angle.sin());
|
||||
Self {
|
||||
|
@ -3,8 +3,10 @@ use crate::library::prelude::*;
|
||||
/// Display a line without affecting the layout.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct LineNode {
|
||||
origin: Spec<Relative>,
|
||||
delta: Spec<Relative>,
|
||||
/// Where the line starts.
|
||||
origin: Spec<Relative<Length>>,
|
||||
/// The offset from the `origin` where the line ends.
|
||||
delta: Spec<Relative<Length>>,
|
||||
}
|
||||
|
||||
#[node]
|
||||
@ -15,14 +17,15 @@ impl LineNode {
|
||||
pub const THICKNESS: Length = Length::pt(1.0);
|
||||
|
||||
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
|
||||
let origin = args.named::<Spec<Relative>>("origin")?.unwrap_or_default();
|
||||
let delta = match args.named::<Spec<Relative>>("to")? {
|
||||
let origin = args.named("origin")?.unwrap_or_default();
|
||||
let delta = match args.named::<Spec<Relative<Length>>>("to")? {
|
||||
Some(to) => to.zip(origin).map(|(to, from)| to - from),
|
||||
None => {
|
||||
let length =
|
||||
args.named::<Relative>("length")?.unwrap_or(Length::cm(1.0).into());
|
||||
let angle = args.named::<Angle>("angle")?.unwrap_or_default();
|
||||
let length = args
|
||||
.named::<Relative<Length>>("length")?
|
||||
.unwrap_or(Length::cm(1.0).into());
|
||||
|
||||
let angle = args.named::<Angle>("angle")?.unwrap_or_default();
|
||||
let x = angle.cos() * length;
|
||||
let y = angle.sin() * length;
|
||||
|
||||
|
@ -28,7 +28,7 @@ impl<const S: ShapeKind> ShapeNode<S> {
|
||||
/// The stroke's thickness.
|
||||
pub const THICKNESS: Length = Length::pt(1.0);
|
||||
/// How much to pad the shape's content.
|
||||
pub const PADDING: Relative = Relative::zero();
|
||||
pub const PADDING: Relative<Length> = Relative::zero();
|
||||
|
||||
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
|
||||
let size = match S {
|
||||
|
@ -29,11 +29,11 @@ impl<const T: TransformKind> TransformNode<T> {
|
||||
MOVE => {
|
||||
let tx = args.named("x")?.unwrap_or_default();
|
||||
let ty = args.named("y")?.unwrap_or_default();
|
||||
Transform::translation(tx, ty)
|
||||
Transform::translate(tx, ty)
|
||||
}
|
||||
ROTATE => {
|
||||
let angle = args.named_or_find("angle")?.unwrap_or_default();
|
||||
Transform::rotation(angle)
|
||||
Transform::rotate(angle)
|
||||
}
|
||||
SCALE | _ => {
|
||||
let all = args.find()?;
|
||||
@ -62,9 +62,9 @@ impl<const T: TransformKind> Layout for TransformNode<T> {
|
||||
|
||||
for frame in &mut frames {
|
||||
let Spec { x, y } = origin.zip(frame.size).map(|(o, s)| o.resolve(s));
|
||||
let transform = Transform::translation(x, y)
|
||||
let transform = Transform::translate(x, y)
|
||||
.pre_concat(self.transform)
|
||||
.pre_concat(Transform::translation(-x, -y));
|
||||
.pre_concat(Transform::translate(-x, -y));
|
||||
|
||||
Arc::make_mut(frame).transform(transform);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ pub struct ColumnsNode {
|
||||
#[node]
|
||||
impl ColumnsNode {
|
||||
/// The size of the gutter space between each column.
|
||||
pub const GUTTER: Relative = Ratio::new(0.04).into();
|
||||
pub const GUTTER: Relative<Length> = Ratio::new(0.04).into();
|
||||
|
||||
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
|
||||
Ok(Content::block(Self {
|
||||
@ -33,7 +33,7 @@ impl Layout for ColumnsNode {
|
||||
) -> TypResult<Vec<Arc<Frame>>> {
|
||||
// Separating the infinite space into infinite columns does not make
|
||||
// much sense.
|
||||
if regions.first.x.is_infinite() {
|
||||
if !regions.first.x.is_finite() {
|
||||
return self.child.layout(ctx, regions, styles);
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ pub enum TrackSizing {
|
||||
Auto,
|
||||
/// A track size specified in absolute terms and relative to the parent's
|
||||
/// size.
|
||||
Relative(Relative),
|
||||
Relative(Relative<Length>),
|
||||
/// A track size specified as a fraction of the remaining free space in the
|
||||
/// parent.
|
||||
Fractional(Fraction),
|
||||
@ -422,7 +422,7 @@ impl<'a> GridLayouter<'a> {
|
||||
fn layout_relative_row(
|
||||
&mut self,
|
||||
ctx: &mut Context,
|
||||
v: Relative,
|
||||
v: Relative<Length>,
|
||||
y: usize,
|
||||
) -> TypResult<()> {
|
||||
let resolved = v.resolve(self.regions.base.y);
|
||||
|
@ -4,7 +4,7 @@ use crate::library::prelude::*;
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct PadNode {
|
||||
/// The amount of padding.
|
||||
pub padding: Sides<Relative>,
|
||||
pub padding: Sides<Relative<Length>>,
|
||||
/// The child node whose sides to pad.
|
||||
pub child: LayoutNode,
|
||||
}
|
||||
@ -54,7 +54,7 @@ impl Layout for PadNode {
|
||||
}
|
||||
|
||||
/// Shrink a size by padding relative to the size itself.
|
||||
fn shrink(size: Size, padding: Sides<Relative>) -> Size {
|
||||
fn shrink(size: Size, padding: Sides<Relative<Length>>) -> Size {
|
||||
size - padding.resolve(size).sum_by_axis()
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ fn shrink(size: Size, padding: Sides<Relative>) -> Size {
|
||||
/// <=> w - p.rel * w - p.abs = s
|
||||
/// <=> (1 - p.rel) * w = s + p.abs
|
||||
/// <=> w = (s + p.abs) / (1 - p.rel)
|
||||
fn grow(size: Size, padding: Sides<Relative>) -> Size {
|
||||
fn grow(size: Size, padding: Sides<Relative<Length>>) -> Size {
|
||||
size.zip(padding.sum_by_axis())
|
||||
.map(|(s, p)| (s + p.abs).safe_div(1.0 - p.rel.get()))
|
||||
}
|
||||
|
@ -16,13 +16,13 @@ impl PageNode {
|
||||
/// Whether the page is flipped into landscape orientation.
|
||||
pub const FLIPPED: bool = false;
|
||||
/// The left margin.
|
||||
pub const LEFT: Smart<Relative> = Smart::Auto;
|
||||
pub const LEFT: Smart<Relative<Length>> = Smart::Auto;
|
||||
/// The right margin.
|
||||
pub const RIGHT: Smart<Relative> = Smart::Auto;
|
||||
pub const RIGHT: Smart<Relative<Length>> = Smart::Auto;
|
||||
/// The top margin.
|
||||
pub const TOP: Smart<Relative> = Smart::Auto;
|
||||
pub const TOP: Smart<Relative<Length>> = Smart::Auto;
|
||||
/// The bottom margin.
|
||||
pub const BOTTOM: Smart<Relative> = Smart::Auto;
|
||||
pub const BOTTOM: Smart<Relative<Length>> = Smart::Auto;
|
||||
/// The page's background color.
|
||||
pub const FILL: Option<Paint> = None;
|
||||
/// How many columns the page has.
|
||||
@ -85,7 +85,7 @@ impl PageNode {
|
||||
}
|
||||
|
||||
let mut min = width.min(height);
|
||||
if min.is_infinite() {
|
||||
if !min.is_finite() {
|
||||
min = Paper::A4.width();
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ impl PageNode {
|
||||
}
|
||||
|
||||
// Layout the child.
|
||||
let regions = Regions::repeat(size, size, size.map(Length::is_finite));
|
||||
let regions = Regions::repeat(size, size, size.map(Numeric::is_finite));
|
||||
let mut frames = child.layout(ctx, ®ions, styles)?;
|
||||
|
||||
let header = styles.get(Self::HEADER);
|
||||
@ -133,7 +133,7 @@ impl PageNode {
|
||||
let pos = Point::new(padding.left, y);
|
||||
let w = size.x - padding.left - padding.right;
|
||||
let area = Size::new(w, h);
|
||||
let pod = Regions::one(area, area, area.map(Length::is_finite));
|
||||
let pod = Regions::one(area, area, area.map(Numeric::is_finite));
|
||||
let sub = Layout::layout(&content, ctx, &pod, styles)?.remove(0);
|
||||
Arc::make_mut(frame).push_frame(pos, sub);
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ impl VNode {
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum Spacing {
|
||||
/// Spacing specified in absolute terms and relative to the parent's size.
|
||||
Relative(Relative),
|
||||
Relative(Relative<Length>),
|
||||
/// Spacing specified as a fraction of the remaining free space in the parent.
|
||||
Fractional(Fraction),
|
||||
}
|
||||
|
@ -167,16 +167,13 @@ castable! {
|
||||
}
|
||||
|
||||
castable! {
|
||||
Spec<Relative>,
|
||||
Spec<Relative<Length>>,
|
||||
Expected: "array of two relative lengths",
|
||||
Value::Array(array) => {
|
||||
match array.as_slice() {
|
||||
[a, b] => {
|
||||
let a = a.clone().cast::<Relative>()?;
|
||||
let b = b.clone().cast::<Relative>()?;
|
||||
Spec::new(a, b)
|
||||
},
|
||||
_ => return Err("point array must contain exactly two entries".to_string()),
|
||||
let mut iter = array.into_iter();
|
||||
match (iter.next(), iter.next(), iter.next()) {
|
||||
(Some(a), Some(b), None) => Spec::new(a.cast()?, b.cast()?),
|
||||
_ => Err("point array must contain exactly two entries")?,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -34,11 +34,11 @@ impl<const L: ListKind> ListNode<L> {
|
||||
#[property(referenced)]
|
||||
pub const LABEL: Label = Label::Default;
|
||||
/// The spacing between the list items of a non-wide list.
|
||||
pub const SPACING: Relative = Relative::zero();
|
||||
pub const SPACING: Relative<Length> = Relative::zero();
|
||||
/// The indentation of each item's label.
|
||||
pub const INDENT: Relative = Ratio::new(0.0).into();
|
||||
pub const INDENT: Relative<Length> = Ratio::new(0.0).into();
|
||||
/// The space between the label and the body of each item.
|
||||
pub const BODY_INDENT: Relative = Ratio::new(0.5).into();
|
||||
pub const BODY_INDENT: Relative<Length> = Ratio::new(0.5).into();
|
||||
/// The extra padding above the list.
|
||||
pub const ABOVE: Length = Length::zero();
|
||||
/// The extra padding below the list.
|
||||
|
@ -23,7 +23,7 @@ impl TableNode {
|
||||
/// The stroke's thickness.
|
||||
pub const THICKNESS: Length = Length::pt(1.0);
|
||||
/// How much to pad the cells's content.
|
||||
pub const PADDING: Relative = Length::pt(5.0).into();
|
||||
pub const PADDING: Relative<Length> = Length::pt(5.0).into();
|
||||
|
||||
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
|
||||
let columns = args.named("columns")?.unwrap_or_default();
|
||||
|
@ -26,13 +26,13 @@ impl<const L: DecoLine> DecoNode<L> {
|
||||
/// Thickness of the line's strokes (dependent on scaled font size), read
|
||||
/// from the font tables if `None`.
|
||||
#[property(shorthand)]
|
||||
pub const THICKNESS: Option<Relative> = None;
|
||||
pub const THICKNESS: Option<Relative<Length>> = None;
|
||||
/// Position of the line relative to the baseline (dependent on scaled font
|
||||
/// size), read from the font tables if `None`.
|
||||
pub const OFFSET: Option<Relative> = None;
|
||||
pub const OFFSET: Option<Relative<Length>> = None;
|
||||
/// Amount that the line will be longer or shorter than its associated text
|
||||
/// (dependent on scaled font size).
|
||||
pub const EXTENT: Relative = Relative::zero();
|
||||
pub const EXTENT: Relative<Length> = Relative::zero();
|
||||
/// Whether the line skips sections in which it would collide
|
||||
/// with the glyphs. Does not apply to strikethrough.
|
||||
pub const EVADE: bool = true;
|
||||
@ -66,9 +66,9 @@ impl<const L: DecoLine> Show for DecoNode<L> {
|
||||
pub struct Decoration {
|
||||
pub line: DecoLine,
|
||||
pub stroke: Option<Paint>,
|
||||
pub thickness: Option<Relative>,
|
||||
pub offset: Option<Relative>,
|
||||
pub extent: Relative,
|
||||
pub thickness: Option<Relative<Length>>,
|
||||
pub offset: Option<Relative<Length>>,
|
||||
pub extent: Relative<Length>,
|
||||
pub evade: bool,
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ castable! {
|
||||
|
||||
/// The size of text.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct FontSize(pub Relative);
|
||||
pub struct FontSize(pub Relative<Length>);
|
||||
|
||||
impl Fold for FontSize {
|
||||
type Output = Length;
|
||||
|
@ -42,11 +42,11 @@ impl ParNode {
|
||||
/// will will be hyphenated if and only if justification is enabled.
|
||||
pub const HYPHENATE: Smart<bool> = Smart::Auto;
|
||||
/// The spacing between lines (dependent on scaled font size).
|
||||
pub const LEADING: Relative = Ratio::new(0.65).into();
|
||||
pub const LEADING: Relative<Length> = Ratio::new(0.65).into();
|
||||
/// The extra spacing between paragraphs (dependent on scaled font size).
|
||||
pub const SPACING: Relative = Ratio::new(0.55).into();
|
||||
pub const SPACING: Relative<Length> = Ratio::new(0.55).into();
|
||||
/// The indent the first line of a consecutive paragraph should have.
|
||||
pub const INDENT: Relative = Relative::zero();
|
||||
pub const INDENT: Relative<Length> = Relative::zero();
|
||||
|
||||
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
|
||||
// The paragraph constructor is special: It doesn't create a paragraph
|
||||
|
@ -8,7 +8,7 @@ pub fn rgb(_: &mut Context, args: &mut Args) -> TypResult<Value> {
|
||||
if let Some(string) = args.find::<Spanned<EcoString>>()? {
|
||||
match RgbaColor::from_str(&string.v) {
|
||||
Ok(color) => color,
|
||||
Err(_) => bail!(string.span, "invalid hex string"),
|
||||
Err(msg) => bail!(string.span, msg),
|
||||
}
|
||||
} else {
|
||||
struct Component(u8);
|
||||
|
@ -20,7 +20,7 @@
|
||||
#test(rgb(-30, 15, 50))
|
||||
|
||||
---
|
||||
// Error: 6-11 invalid hex string
|
||||
// Error: 6-11 string contains non-hexadecimal letters
|
||||
#rgb("lol")
|
||||
|
||||
---
|
||||
|
Loading…
x
Reference in New Issue
Block a user