typst_library/layout/
dir.rs

1use ecow::EcoString;
2
3use crate::foundations::{Repr, func, scope, ty};
4use crate::layout::{Axis, Side};
5
6/// The four directions into which content can be laid out.
7///
8///  Possible values are:
9/// - `{ltr}`: Left to right.
10/// - `{rtl}`: Right to left.
11/// - `{ttb}`: Top to bottom.
12/// - `{btt}`: Bottom to top.
13///
14/// These values are available globally and
15/// also in the direction type's scope, so you can write either of the following
16/// two:
17/// ```example
18/// #stack(dir: rtl)[A][B][C]
19/// #stack(dir: direction.rtl)[A][B][C]
20/// ```
21#[ty(scope, name = "direction")]
22#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
23pub enum Dir {
24    /// Left to right.
25    LTR,
26    /// Right to left.
27    RTL,
28    /// Top to bottom.
29    TTB,
30    /// Bottom to top.
31    BTT,
32}
33
34impl Dir {
35    /// Whether this direction points into the positive coordinate direction.
36    ///
37    /// The positive directions are left-to-right and top-to-bottom.
38    pub const fn is_positive(self) -> bool {
39        match self {
40            Self::LTR | Self::TTB => true,
41            Self::RTL | Self::BTT => false,
42        }
43    }
44}
45
46#[scope]
47impl Dir {
48    pub const LTR: Self = Self::LTR;
49    pub const RTL: Self = Self::RTL;
50    pub const TTB: Self = Self::TTB;
51    pub const BTT: Self = Self::BTT;
52
53    /// Returns a direction from a starting point.
54    ///
55    /// ```example
56    /// #direction.from(left) \
57    /// #direction.from(right) \
58    /// #direction.from(top) \
59    /// #direction.from(bottom)
60    /// ```
61    #[func]
62    pub const fn from(side: Side) -> Dir {
63        match side {
64            Side::Left => Self::LTR,
65            Side::Right => Self::RTL,
66            Side::Top => Self::TTB,
67            Side::Bottom => Self::BTT,
68        }
69    }
70
71    /// Returns a direction from an end point.
72    ///
73    /// ```example
74    /// #direction.to(left) \
75    /// #direction.to(right) \
76    /// #direction.to(top) \
77    /// #direction.to(bottom)
78    /// ```
79    #[func]
80    pub const fn to(side: Side) -> Dir {
81        match side {
82            Side::Right => Self::LTR,
83            Side::Left => Self::RTL,
84            Side::Bottom => Self::TTB,
85            Side::Top => Self::BTT,
86        }
87    }
88
89    /// The axis this direction belongs to, either `{"horizontal"}` or
90    /// `{"vertical"}`.
91    ///
92    /// ```example
93    /// #ltr.axis() \
94    /// #ttb.axis()
95    /// ```
96    #[func]
97    pub const fn axis(self) -> Axis {
98        match self {
99            Self::LTR | Self::RTL => Axis::X,
100            Self::TTB | Self::BTT => Axis::Y,
101        }
102    }
103
104    /// The corresponding sign, for use in calculations.
105    ///
106    /// ```example
107    /// #ltr.sign() \
108    /// #rtl.sign() \
109    /// #ttb.sign() \
110    /// #btt.sign()
111    /// ```
112    #[func]
113    pub const fn sign(self) -> i64 {
114        match self {
115            Self::LTR | Self::TTB => 1,
116            Self::RTL | Self::BTT => -1,
117        }
118    }
119
120    /// The start point of this direction, as an alignment.
121    ///
122    /// ```example
123    /// #ltr.start() \
124    /// #rtl.start() \
125    /// #ttb.start() \
126    /// #btt.start()
127    /// ```
128    #[func]
129    pub const fn start(self) -> Side {
130        match self {
131            Self::LTR => Side::Left,
132            Self::RTL => Side::Right,
133            Self::TTB => Side::Top,
134            Self::BTT => Side::Bottom,
135        }
136    }
137
138    /// The end point of this direction, as an alignment.
139    ///
140    /// ```example
141    /// #ltr.end() \
142    /// #rtl.end() \
143    /// #ttb.end() \
144    /// #btt.end()
145    /// ```
146    #[func]
147    pub const fn end(self) -> Side {
148        match self {
149            Self::LTR => Side::Right,
150            Self::RTL => Side::Left,
151            Self::TTB => Side::Bottom,
152            Self::BTT => Side::Top,
153        }
154    }
155
156    /// The inverse direction.
157    ///
158    /// ```example
159    /// #ltr.inv() \
160    /// #rtl.inv() \
161    /// #ttb.inv() \
162    /// #btt.inv()
163    /// ```
164    #[func(title = "Inverse")]
165    pub const fn inv(self) -> Dir {
166        match self {
167            Self::LTR => Self::RTL,
168            Self::RTL => Self::LTR,
169            Self::TTB => Self::BTT,
170            Self::BTT => Self::TTB,
171        }
172    }
173}
174
175impl Repr for Dir {
176    fn repr(&self) -> EcoString {
177        match self {
178            Self::LTR => "ltr".into(),
179            Self::RTL => "rtl".into(),
180            Self::TTB => "ttb".into(),
181            Self::BTT => "btt".into(),
182        }
183    }
184}