diff options
Diffstat (limited to 'crates/typst-library/src/math/cancel.rs')
| -rw-r--r-- | crates/typst-library/src/math/cancel.rs | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/crates/typst-library/src/math/cancel.rs b/crates/typst-library/src/math/cancel.rs new file mode 100644 index 00000000..a72505c0 --- /dev/null +++ b/crates/typst-library/src/math/cancel.rs @@ -0,0 +1,116 @@ +use crate::foundations::{cast, elem, Content, Func, Smart}; +use crate::layout::{Abs, Angle, Length, Ratio, Rel}; +use crate::math::Mathy; +use crate::visualize::Stroke; + +/// Displays a diagonal line over a part of an equation. +/// +/// This is commonly used to show the elimination of a term. +/// +/// # Example +/// ```example +/// >>> #set page(width: 140pt) +/// Here, we can simplify: +/// $ (a dot b dot cancel(x)) / +/// cancel(x) $ +/// ``` +#[elem(Mathy)] +pub struct CancelElem { + /// The content over which the line should be placed. + #[required] + pub body: Content, + + /// The length of the line, relative to the length of the diagonal spanning + /// the whole element being "cancelled". A value of `{100%}` would then have + /// the line span precisely the element's diagonal. + /// + /// ```example + /// >>> #set page(width: 140pt) + /// $ a + cancel(x, length: #200%) + /// - cancel(x, length: #200%) $ + /// ``` + #[default(Rel::new(Ratio::one(), Abs::pt(3.0).into()))] + pub length: Rel<Length>, + + /// Whether the cancel line should be inverted (flipped along the y-axis). + /// For the default angle setting, inverted means the cancel line + /// points to the top left instead of top right. + /// + /// ```example + /// >>> #set page(width: 140pt) + /// $ (a cancel((b + c), inverted: #true)) / + /// cancel(b + c, inverted: #true) $ + /// ``` + #[default(false)] + pub inverted: bool, + + /// Whether two opposing cancel lines should be drawn, forming a cross over + /// the element. Overrides `inverted`. + /// + /// ```example + /// >>> #set page(width: 140pt) + /// $ cancel(Pi, cross: #true) $ + /// ``` + #[default(false)] + pub cross: bool, + + /// How much to rotate the cancel line. + /// + /// - If given an angle, the line is rotated by that angle clockwise with + /// respect to the y-axis. + /// - If `{auto}`, the line assumes the default angle; that is, along the + /// rising diagonal of the content box. + /// - If given a function `angle => angle`, the line is rotated, with + /// respect to the y-axis, by the angle returned by that function. The + /// function receives the default angle as its input. + /// + /// ```example + /// >>> #set page(width: 140pt) + /// $ cancel(Pi) + /// cancel(Pi, angle: #0deg) + /// cancel(Pi, angle: #45deg) + /// cancel(Pi, angle: #90deg) + /// cancel(1/(1+x), angle: #(a => a + 45deg)) + /// cancel(1/(1+x), angle: #(a => a + 90deg)) $ + /// ``` + pub angle: Smart<CancelAngle>, + + /// How to [stroke]($stroke) the cancel line. + /// + /// ```example + /// >>> #set page(width: 140pt) + /// $ cancel( + /// sum x, + /// stroke: #( + /// paint: red, + /// thickness: 1.5pt, + /// dash: "dashed", + /// ), + /// ) $ + /// ``` + #[resolve] + #[fold] + #[default(Stroke { + // Default stroke has 0.5pt for better visuals. + thickness: Smart::Custom(Abs::pt(0.5).into()), + ..Default::default() + })] + pub stroke: Stroke, +} + +/// Defines the cancel line. +#[derive(Debug, Clone, PartialEq, Hash)] +pub enum CancelAngle { + Angle(Angle), + Func(Func), +} + +cast! { + CancelAngle, + self => match self { + Self::Angle(v) => v.into_value(), + Self::Func(v) => v.into_value() + }, + v: Angle => CancelAngle::Angle(v), + v: Func => CancelAngle::Func(v), +} |
