1 //! Direction-related structures.
2 //!
3 //! This module defines two main concepts: [`Orientation`] and [`Direction`].
4 //!
5 //! [`Orientation`]: enum.Orientation.html
6 //! [`Direction`]: enum.Direction.html
7 //!
8 //! ### Orientation
9 //!
10 //! `Orientation` is a simple enum that can take two values:
11 //! `Horizontal` or `Vertical`.
12 //!
13 //! ### Direction
14 //!
15 //! `Direction` is a bit more complex, and can be of two kinds:
16 //!
17 //! * Absolute direction: left, up, right, or down
18 //! * Relative direction: front or back. Its actual direction depends on the
19 //!   orientation.
20 //!
21 //!   Usually, "front" refers to the "forward" direction, or the "next"
22 //!   element. For example, for a vertical `LinearLayout`, "front" would refer
23 //!   to the "down" direction.
24 //!
25 //!   This is mostly relevant when referring to change of focus. Hitting the
26 //!   `Tab` key would usually cycle focus in the "front" direction, while
27 //!   using the arrow keys would use absolute directions instead.
28 
29 use crate::Vec2;
30 use crate::XY;
31 
32 /// Describes a vertical or horizontal orientation for a view.
33 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
34 pub enum Orientation {
35     /// Horizontal orientation
36     Horizontal,
37     /// Vertical orientation
38     Vertical,
39 }
40 
41 impl Orientation {
42     /// Returns a `XY(Horizontal, Vertical)`.
pair() -> XY<Orientation>43     pub fn pair() -> XY<Orientation> {
44         XY::new(Orientation::Horizontal, Orientation::Vertical)
45     }
46 
47     /// Returns the component of `v` corresponding to this orientation.
48     ///
49     /// (`Horizontal` will return the x value,
50     /// and `Vertical` will return the y value.)
get<T: Clone>(self, v: &XY<T>) -> T51     pub fn get<T: Clone>(self, v: &XY<T>) -> T {
52         v.get(self).clone()
53     }
54 
55     /// Returns the other orientation.
swap(self) -> Self56     pub fn swap(self) -> Self {
57         match self {
58             Orientation::Horizontal => Orientation::Vertical,
59             Orientation::Vertical => Orientation::Horizontal,
60         }
61     }
62 
63     /// Returns a mutable reference to the component of the given vector
64     /// corresponding to this orientation.
65     ///
66     /// # Examples
67     /// ```rust
68     /// # use cursive_core::XY;
69     /// # use cursive_core::direction::Orientation;
70     /// let o = Orientation::Horizontal;
71     /// let mut xy = XY::new(1, 2);
72     /// *o.get_ref(&mut xy) = 42;
73     ///
74     /// assert_eq!(xy, XY::new(42, 2));
75     /// ```
get_ref<T>(self, v: &mut XY<T>) -> &mut T76     pub fn get_ref<T>(self, v: &mut XY<T>) -> &mut T {
77         match self {
78             Orientation::Horizontal => &mut v.x,
79             Orientation::Vertical => &mut v.y,
80         }
81     }
82 
83     /// Takes an iterator on sizes, and stack them in the current orientation,
84     /// returning the size of the required bounding box.
85     ///
86     /// * For an horizontal view, returns `(Sum(x), Max(y))`.
87     /// * For a vertical view, returns `(Max(x), Sum(y))`.
stack<T: Iterator<Item = Vec2>>(self, iter: T) -> Vec288     pub fn stack<T: Iterator<Item = Vec2>>(self, iter: T) -> Vec2 {
89         match self {
90             Orientation::Horizontal => {
91                 iter.fold(Vec2::zero(), |a, b| a.stack_horizontal(&b))
92             }
93             Orientation::Vertical => {
94                 iter.fold(Vec2::zero(), |a, b| a.stack_vertical(&b))
95             }
96         }
97     }
98 
99     /// Creates a new `Vec2` with `main_axis` in `self`'s axis, and
100     /// `second_axis` for the other axis.
101     ///
102     /// # Examples
103     ///
104     /// ```rust
105     /// # use cursive_core::direction::Orientation;
106     /// # use cursive_core::Vec2;
107     /// let o = Orientation::Horizontal;
108     /// let vec = o.make_vec(1, 2);
109     ///
110     /// assert_eq!(vec, Vec2::new(1, 2));
111     ///
112     /// let o = Orientation::Vertical;
113     /// let vec = o.make_vec(1, 2);
114     ///
115     /// assert_eq!(vec, Vec2::new(2, 1));
116     /// ```
make_vec(self, main_axis: usize, second_axis: usize) -> Vec2117     pub fn make_vec(self, main_axis: usize, second_axis: usize) -> Vec2 {
118         let mut result = Vec2::zero();
119         *self.get_ref(&mut result) = main_axis;
120         *self.swap().get_ref(&mut result) = second_axis;
121         result
122     }
123 }
124 
125 /// Represents a direction, either absolute or orientation-dependent.
126 ///
127 /// * Absolute directions are Up, Down, Left, and Right.
128 /// * Relative directions are Front and Back.
129 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
130 pub enum Direction {
131     /// An absolute direction.
132     Abs(Absolute),
133     /// A direction relative to the current orientation.
134     Rel(Relative),
135 }
136 
137 impl Direction {
138     /// Returns the relative direction for the given orientation.
139     ///
140     /// Some combination have no corresponding relative position. For example,
141     /// `Direction::Abs(Up)` means nothing for `Orientation::Horizontal`.
relative(self, orientation: Orientation) -> Option<Relative>142     pub fn relative(self, orientation: Orientation) -> Option<Relative> {
143         match self {
144             Direction::Abs(abs) => abs.relative(orientation),
145             Direction::Rel(rel) => Some(rel),
146         }
147     }
148 
149     /// Returns the absolute direction in the given `orientation`.
absolute(self, orientation: Orientation) -> Absolute150     pub fn absolute(self, orientation: Orientation) -> Absolute {
151         match self {
152             Direction::Abs(abs) => abs,
153             Direction::Rel(rel) => rel.absolute(orientation),
154         }
155     }
156 
157     /// Returns the direction opposite `self`.
opposite(self) -> Self158     pub fn opposite(self) -> Self {
159         match self {
160             Direction::Abs(abs) => Direction::Abs(abs.opposite()),
161             Direction::Rel(rel) => Direction::Rel(rel.swap()),
162         }
163     }
164 
165     /// Shortcut to create `Direction::Rel(Relative::Back)`
back() -> Self166     pub fn back() -> Self {
167         Direction::Rel(Relative::Back)
168     }
169 
170     /// Shortcut to create `Direction::Rel(Relative::Front)`
front() -> Self171     pub fn front() -> Self {
172         Direction::Rel(Relative::Front)
173     }
174 
175     /// Shortcut to create `Direction::Abs(Absolute::Left)`
left() -> Self176     pub fn left() -> Self {
177         Direction::Abs(Absolute::Left)
178     }
179 
180     /// Shortcut to create `Direction::Abs(Absolute::Right)`
right() -> Self181     pub fn right() -> Self {
182         Direction::Abs(Absolute::Right)
183     }
184 
185     /// Shortcut to create `Direction::Abs(Absolute::Up)`
up() -> Self186     pub fn up() -> Self {
187         Direction::Abs(Absolute::Up)
188     }
189 
190     /// Shortcut to create `Direction::Abs(Absolute::Down)`
down() -> Self191     pub fn down() -> Self {
192         Direction::Abs(Absolute::Down)
193     }
194 
195     /// Shortcut to create `Direction::Abs(Absolute::None)`
none() -> Self196     pub fn none() -> Self {
197         Direction::Abs(Absolute::None)
198     }
199 }
200 
201 /// Direction relative to an orientation.
202 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
203 pub enum Relative {
204     // TODO: handle right-to-left? (Arabic, ...)
205     /// Front relative direction.
206     ///
207     /// * Horizontally, this means `Left`
208     /// * Vertically, this means `Up`
209     Front,
210 
211     /// Back relative direction.
212     ///
213     /// * Horizontally, this means `Right`
214     /// * Vertically, this means `Down`.
215     Back,
216 }
217 
218 impl Relative {
219     /// Returns the absolute direction in the given `orientation`.
absolute(self, orientation: Orientation) -> Absolute220     pub fn absolute(self, orientation: Orientation) -> Absolute {
221         match (orientation, self) {
222             (Orientation::Horizontal, Relative::Front) => Absolute::Left,
223             (Orientation::Horizontal, Relative::Back) => Absolute::Right,
224             (Orientation::Vertical, Relative::Front) => Absolute::Up,
225             (Orientation::Vertical, Relative::Back) => Absolute::Down,
226         }
227     }
228 
229     /// Picks one of the two values in a tuple.
230     ///
231     /// First one is `self` is `Front`, second one if `self` is `Back`.
pick<T>(self, (front, back): (T, T)) -> T232     pub fn pick<T>(self, (front, back): (T, T)) -> T {
233         match self {
234             Relative::Front => front,
235             Relative::Back => back,
236         }
237     }
238 
239     /// Returns the other relative direction.
swap(self) -> Self240     pub fn swap(self) -> Self {
241         match self {
242             Relative::Front => Relative::Back,
243             Relative::Back => Relative::Front,
244         }
245     }
246 
247     /// Returns the relative position of `a` to `b`.
248     ///
249     /// If `a < b`, it would be `Front`.
250     /// If `a > b`, it would be `Back`.
251     /// If `a == b`, returns `None`.
a_to_b(a: usize, b: usize) -> Option<Self>252     pub fn a_to_b(a: usize, b: usize) -> Option<Self> {
253         use std::cmp::Ordering;
254 
255         match a.cmp(&b) {
256             Ordering::Less => Some(Relative::Front),
257             Ordering::Greater => Some(Relative::Back),
258             Ordering::Equal => None,
259         }
260     }
261 }
262 
263 /// Absolute direction (up, down, left, right).
264 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
265 pub enum Absolute {
266     /// Left
267     Left,
268     /// Up
269     Up,
270     /// Right
271     Right,
272     /// Down
273     Down,
274 
275     /// No real direction.
276     ///
277     /// Used when the "direction" is accross layers for instance.
278     None,
279 }
280 
281 impl Absolute {
282     /// Returns the relative direction for the given orientation.
283     ///
284     /// Returns `None` when the direction does not apply to the given
285     /// orientation (ex: `Left` and `Vertical`).
relative(self, orientation: Orientation) -> Option<Relative>286     pub fn relative(self, orientation: Orientation) -> Option<Relative> {
287         match (orientation, self) {
288             (Orientation::Horizontal, Absolute::Left)
289             | (Orientation::Vertical, Absolute::Up) => Some(Relative::Front),
290             (Orientation::Horizontal, Absolute::Right)
291             | (Orientation::Vertical, Absolute::Down) => Some(Relative::Back),
292             _ => None,
293         }
294     }
295 
296     /// Returns the direction opposite `self`.
opposite(self) -> Self297     pub fn opposite(self) -> Self {
298         match self {
299             Absolute::Left => Absolute::Right,
300             Absolute::Right => Absolute::Left,
301             Absolute::Up => Absolute::Down,
302             Absolute::Down => Absolute::Up,
303             Absolute::None => Absolute::None,
304         }
305     }
306 
307     /// Splits this absolute direction into an orientation and relative direction.
308     ///
309     /// For example, `Right` will give `(Horizontal, Back)`.
split(self) -> (Orientation, Relative)310     pub fn split(self) -> (Orientation, Relative) {
311         match self {
312             Absolute::Left => (Orientation::Horizontal, Relative::Front),
313             Absolute::Right => (Orientation::Horizontal, Relative::Back),
314             Absolute::Up => (Orientation::Vertical, Relative::Front),
315             Absolute::Down => (Orientation::Vertical, Relative::Back),
316             // TODO: Remove `Absolute::None`
317             Absolute::None => panic!("None direction not supported here"),
318         }
319     }
320 }
321