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}